Reputation: 2103
I have the following component:
import React from 'react';
import './styles.css';
import ToolTip from '../../Common/components/ToolTip/ToolTip';
export default class RouteTitleTooltipComponent extends React.Component {
constructor(props) {
super(props);
this.titleParagraphRef = React.createRef();
this._tooltipTimer = null;
this.state = { shouldPopupBeEnabled: false, isTooltipShown: false };
this._showTooltip = this._showTooltip.bind(this);
this._hideTooltip = this._hideTooltip.bind(this);
}
componentDidMount() {
const { scrollWidth, clientWidth } = this.titleParagraphRef.current;
const shouldPopupBeEnabled = scrollWidth > clientWidth;
this.setState({ shouldPopupBeEnabled });
}
_showTooltip() {
this._tooltipTimer = setTimeout(
() => {
this.setState({ isTooltipShown: true });
}, 1000,
);
}
_hideTooltip() {
clearTimeout(this._tooltipTimer);
this.setState({ isTooltipShown: false });
}
render() {
const { shouldPopupBeEnabled, isTooltipShown } = this.state;
const { message } = this.props;
return (
<ToolTip
message="Tooltip!!"
popoverOpen={shouldPopupBeEnabled && isTooltipShown}
>
<div
ref={this.titleParagraphRef}
onMouseOver={this._showTooltip}
>
{message}
</div>
</ToolTip>
);
}
}
This basically renders a floating tooltip over a div element if the message inside of it is bigger than the container. To do that, I use scrollWidth
and clientWidth
of the div element using a React reference. To detect those values I use componentDidMount
, but this only works in full renders of the component. That is, if I have the component visible and reload the page, both values are equal to 0 and it does not work.
In addition, if I change the message, it does not work either because the component is already mounted.
So what I want is to change the state right after the component is mounted or updated so that the react reference is rendered and clientWidth
and scrollWidth
are not 0.
I have tried replace componentDidUpdate
instead of componentDidMount
but it's not a good practica to use setState
inside componentDidUpdate
.
Any solution?
Upvotes: 0
Views: 231
Reputation: 968
First you should know that componentDidMount
will execute only once. Therefor you can go for componentDidUpdate
but don't forget to put a condition as it will render in a loop.
componentDidUpdate(prevProps,prevState) {
const shouldPopupBeEnabled = scrollWidth > clientWidth;
if (shouldPopupBeEnabled !== this.state.shouldPopupBeEnabled ) {
this.setState({shouldPopupBeEnabled });
}
}
Or you can go for functional components and use useEffect which will only render again if state changes.
useEffect(() => {
console.log('mounted');
}, [shouldPopupBeEnabled]) // It will re render id `shouldPopupBeEnabled` changes
Upvotes: 1