5

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
c137
  • 181
  • 9
  • Are you running in a development environment with `StrictMode` on, in a React version above 16.8.0? Many functions are intentionally called twice in that case to assist in debugging side effects, but in a production build they are only called once, as you would expect. – DaveVanFleet Dec 31 '21 at 19:27
  • I just tried to remove the `StrictMode` in my app and it behave the same. React version is `17.0.2` – c137 Dec 31 '21 at 19:41
  • Does this answer your question? [Why React needs another render to bail out state updates?](https://stackoverflow.com/questions/58208727/why-react-needs-another-render-to-bail-out-state-updates) – HDM91 Dec 31 '21 at 19:57
  • In general, "why does React call my component function more than once" is an unnecessary question. React is absolutely at its leisure to call your function as many times as it pleases; that's why the function is supposed to be pure (aside from hooks). – AKX Dec 31 '21 at 20:04

1 Answers1

1

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

HDM91
  • 1,318
  • 9
  • 16
  • did you see this post about differences between class component and function compoennt and useState , setState? https://stackoverflow.com/questions/55373878/what-are-the-differences-when-re-rendering-after-state-was-set-with-hooks-compar – HDM91 Dec 31 '21 at 19:34
  • its not related to scroll or anything its react that says: 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 tre – HDM91 Dec 31 '21 at 19:35
  • see this post i hope help you : https://stackoverflow.com/questions/58208727/why-react-needs-another-render-to-bail-out-state-updates – HDM91 Dec 31 '21 at 19:45
  • https://github.com/facebook/react/issues/14994#issuecomment-468779750 – HDM91 Dec 31 '21 at 19:53
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/240621/discussion-between-hdm91-and-hartatovich). – HDM91 Dec 31 '21 at 19:55