I need to be able to position a React DOM element by its offsetHeight.
The problem is that I can't gather the offsetHeight of an element that hasn't been created yet (so the height cannot be passed to the render function as a parameter) and I also cannot calculate the height inside of the render function as noted in the React DOM refs docs:
Never access refs inside of any ponent's render method – or while any ponent's render method is even running anywhere in the call stack.
The DOM element should render relative to an icon that is clicked to display it.
The ponent tree:
|— FormInputGroup
|— Label
|— TooltipIcon
|— Tooltip
|— Input
I need to be able to position a React DOM element by its offsetHeight.
The problem is that I can't gather the offsetHeight of an element that hasn't been created yet (so the height cannot be passed to the render function as a parameter) and I also cannot calculate the height inside of the render function as noted in the React DOM refs docs:
Never access refs inside of any ponent's render method – or while any ponent's render method is even running anywhere in the call stack.
The DOM element should render relative to an icon that is clicked to display it.
The ponent tree:
|— FormInputGroup
|— Label
|— TooltipIcon
|— Tooltip
|— Input
The render function for the tooltip-icon:
const TooltipIcon = ({ attribute, setCurrentTooltip }) => (
<Icon
name="tooltip"
style={{
position: "relative",
top: "1px",
marginLeft: "10px",
"cursor": "pointer",
}}
onClick={() => setCurrentTooltip(attribute)}
/>
)
The render function:
const Tooltip = ({ title, content, setCurrentTooltip }) => (
<div className="popover"
style={{
// top: "-"+ ReactDOM.findDOMNode(this).offsetHeight +"px",
}}
>
<h3 className="popover-title">{title}</h3>
<div className="popover-close-button"
onClick={() => setCurrentTooltip(null)}
/>
<div className="popover-content">{content}</div>
</div>
)
Here is the DOM element without the positioning: not positioned
Here is how I would like the position to be rendered (with top: -(offsetHeight)px: positioned
Share Improve this question asked May 17, 2016 at 0:56 cmwallcmwall 4672 gold badges6 silver badges15 bronze badges2 Answers
Reset to default 3Not sure it's the best solution, but one technique you can use is to keep track of your style through ponent state, initializing it to be empty at first:
this.state = { style: {} };
And then updating that state in a ponentDidMount()
function once you can successfully access the element you are looking for:
ponentDidMount() {
this.setState(
{style: { top: "-" + (ReactDOM.findDOMNode(this).offsetHeight) + "px" } }
);
}
Passing it down as a prop if need be to any child ponent that needs it.
I put together a codepen with some ments to illustrate a little further: http://codepen.io/anon/pen/vGwyVj
I had a similar problem myself, one work around is to use the lifecycle method ponentDidMount
, as such you will need to use a controlled or 'smart' ponent.
DEMO
class Tooltip extends React.ponent {
constructor(props) {
super(props);
this.state = {
mounted: false,
... other state stuff
};
}
....
}
in ponentDidMount
you set the state of mounted
to true, here you will also have access to your ponent:
ponentDidMount() {
this.setState({mounted: true})
// get your style here...
}
then in your render function you conditionally render the ponent based on that state:
render() {
if (this.state.mounted) {
// return your ponent with the offset style
// which you can pass in as a prop...
} else {
// you can return a version of the ponent that is not offset here,
// I chose not to do this, React is pretty fast.
}
}