I'm trying to run a function to check the contrast of any DOM node against its background, passing a reference to the node itself as an argument. But on the initial render, the ref value stays null
, I don't understand why.
I understand using useLayoutEffect
instead of useEffect
should fire synchronously. Also, maybe the issue is with the ref itself, but shouldn't the useRef
do the trick?
Here's a sandbox with the full code.
This is the component part:
function App() {
const ref = useRef(null);
const contrast = useContrast(ref);
return (
<div className="App">
<h1 ref={ref}>Contrast: {contrast}</h1>
</div>
);
}
And the custom hook part:
export default function useContrast(ref) {
const [contrast, setContrast] = useState("");
if (!!ref.current) {
useLayoutEffect(() => {
const contrast = contrastValidation(
getForegroundColor(ref.current),
getBackgroundColor(ref.current)
);
setContrast(contrast);
});
return ref.current;
}
return contrast;
}
It should display some contrast value here: <h1 ref={ref}>Contrast: {contrast}</h1>
, but all I get stays null
(as it is defined by default with the useRef
).
ref.current
will be set inside the function given to useLayoutEffect
, but it will not be set before it, so you can't do if (!!ref.current) { ... }
to conditionally use the hook or not. You should not put hooks inside conditional logic at all.
This will work as you expect since state updates that occur inside the function given to useLayoutEffect
will be flushed synchronously, before the browser has a chance to paint.
export default function useContrast(ref) {
const [contrast, setContrast] = useState("");
useLayoutEffect(() => {
const contrast = contrastValidation(
getForegroundColor(ref.current),
getBackgroundColor(ref.current)
);
setContrast(contrast);
});
return contrast;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With