Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS double render for a Boolean state with useState

I'm just playing around with ReactJS and trying to figure out some strange behavior with the useState hook.

A component should not re-rendered if the state is set with the same primitive value (Boolean) as it was before

const useScroll = ({positionToCross = 10}) => {

    const window = useWindow();
    const [isPositionCrossed, setIsPositionCrossed] = useState(window.scrollY > positionToCross);

    useEffect(() => {

        const onScroll = function (e) {

            window.requestAnimationFrame(function () {
                const lastKnownScrollPosition = window.scrollY;
                setIsPositionCrossed(lastKnownScrollPosition > positionToCross);
            });

        }

        window.addEventListener('scroll', onScroll);

        return () => {
            window.removeEventListener("scroll", onScroll)
        }

    }, []);


    console.log(`useScroll - render window.scrollY = ${window.scrollY.toFixed(0)} isPositionCrossed = `, isPositionCrossed)
    return {isPositionCrossed}
}

here is the console output - you can see the component and the hook are both rendered two times with "true" (after scrolled over 100px)

"useScroll - render window.scrollY = 101 isPositionCrossed = ", true
"useScroll - render window.scrollY = 103 isPositionCrossed = ", true
like image 843
c137 Avatar asked Nov 06 '22 23:11

c137


1 Answers

If you try simple code that on click handler setState and if you click two times and in each update state with same value the component again re-render. As react doc says:

If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is comparison algorithm.)

Note that React may still need to render that specific component again before bailing out. That shouldn’t be a concern because React won’t unnecessarily go “deeper” into the tree. If you’re doing expensive calculations while rendering, you can optimize them with useMemo.

I hope the answers from this post and this github discussion help you to understand why this happens

and there are another related topics like this post and this one

like image 118
HDM91 Avatar answered Nov 12 '22 18:11

HDM91