I have a React functional component in which I have some input fields, a button, and a tooltip. The tooltip is disabled by default and should only be enabled and visible if the button is clicked while the input fields have invalid values.
The problem is that the tooltip is only appearing if I press the button twice. I used console.log
to debug the state value in the handleOnClick
method when the fields are invalid, and right after the setEnableTooltip(true)
call, enableTooltip
is still false. Afterwards, if I have a log printing enableTooltip
in MyComponent
, it prints true, but it still doesn’t show the tooltip – it only shows when I click the button for the second time.
Simplifying the code by not showing the specifics of InputFields, Tooltips, and Button because they’re from different libraries.
const handleOnClick = (setEnableTooltip: React.Dispatch<React.SetStateAction<boolean>>) => {
if (fieldsInvalid()) {
setEnableTooltip(true);
} else {
setEnableTooltip(false);
}
}
const MyComponent = () => {
const [enableTooltip, setEnableTooltip] = useState(false);
return (
<InputFields />
<Tooltip disabled={!enableTooltip}>
<Button slot="trigger" onClick={() => handleOnClick(setEnableTooltip)} />
Tooltip text
</Tooltip>
}
}
I did some research here and saw that this is most likely happening because setState is asynchronous, and some solutions could be to use callbacks or useEffect. I tried these but am having no success.
This doesn’t display the tooltip at all when I click the button multiple times:
const handleOnClick = (setEnableTooltip: React.Dispatch<React.SetStateAction<boolean>>) => {
if (fieldsInvalid()) {
setEnableTooltip(prevState => !prevState);
} else {
setEnableTooltip(prevState => !prevState);
}
}
I also tried creating another state variable and using useEffect to react to the state changing, but this still only displays the tooltip after the second click:
const handleOnClick = (setIsInvalidValue: React.Dispatch<React.SetStateAction<boolean>>) => {
if (fieldsInvalid()) {
setIsInvalidValue(true);
} else {
setIsInvalidValue(false);
}
}
const MyComponent = () => {
const [enableTooltip, setEnableTooltip] = useState(false);
const [isInvalidValue, setIsInvalidValue] = useState(false);
useEffect(() => {
setEnableTooltip(isInvalidValue);
}, [isInvalidValue]);
return (
<InputFields />
<Tooltip disabled={!enableTooltip}>
<Button slot="trigger" onClick={() => handleOnClick(setIsInvalidValue)} />
Tooltip text
</Tooltip>
}
}
At this point I’m stuck and at a loss for options. Does anyone have any tips on what I can do?
2
Answers
You don’t need to pass setState in handleOnclick. Just simply call the function like this:
and your function like this:
also you do need to elaborate a bit more on your fieldsInvalid function. You’re not passing anything into the function so we don’t know what value you are returning. Also bring your function inside the component.
We need additional information about how you’re validating your input.
To assist you, here’s an example that closely resembles what you’re trying to achieve.
=> example