0

I am using useRef hook in a layout component to detect the scroll value of it's children (pageContent). I am then conditionally displaying a button to scroll back to top.

Functionalities are working as excepted, but when I console.log something inside the pageComponent children (<route.component/>), it's shows me that the component is re-rendering each time the button shows / hide (scrollTop Value crosses 500)

Here is my Layout component :

function Layout() {
    const [showBackToTopButton, setShowBackToTopButton] = useState(false);
    const pageContentRef = useRef<HTMLDivElement>(null);

    function handleScroll() {
        const mainContent = pageContentRef.current;
        if (mainContent) {
            if (mainContent.scrollTop > 500) {
                setShowBackToTopButton(true);
            } else {
                setShowBackToTopButton(false);
            }
        }
    }

    function handleClickBackTop() {
        const mainContent = pageContentRef.current;
        if (mainContent) mainContent.scrollTo({ top: 0, behavior: 'smooth' });
    }

    useEffect(() => {
        const mainContent = pageContentRef.current;
        if (mainContent)
            mainContent.onscroll = function () {
                handleScroll();
            };
    }, []);

    return (
        <>
            <div className='drawer drawer-mobile'>
                <input
                    id='left-sidebar-drawer'
                    type='checkbox'
                    className='drawer-toggle'
                />
                <PageContent pageContentRef={pageContentRef} />
                <LeftSidebar />
            </div>

            {showBackToTopButton && (
                <Button
                    className='back-to-top-button absolute right-0 bottom-10'
                    id='back-to-top'
                    onClick={handleClickBackTop}
                >
                    <i className='fa-solid fa-arrow-up' />
                </Button>
            )}
        </>
    );
}

export default Layout;

and here is the PageContent component :

interface PageContentProps {
    pageContentRef: React.RefObject<HTMLDivElement>;
}

function PageContent({ pageContentRef }: PageContentProps) {
    return (
        <div className='drawer-content flex flex-col '>
            <Header />
            <main className='flex-1 overflow-y-auto pt-8 px-6' ref={pageContentRef}>
                <Suspense fallback={<SuspenseContent />}>
                    <Routes>
                        {routes.map((route, key) => {
                            return (
                                <Route
                                    key={key}
                                    path={`${route.path}`}
                                    element={<route.component name={route.name} />}
                                />
                            );
                        })}

                        {/* Redirecting unknown url to 404 page */}
                        <Route path='*' element={<NotFound />} />
                    </Routes>
                </Suspense>
            </main>
        </div>
    );
}

export default PageContent;

Is it a normal behaviour considering the useState value ?

I tried using useMemo but I did not manage to solve my issue.

It's not a very big deal since the component are not rendering tenths of times, but it would be cleaner if they could render only once...

2 Answers 2

1

The reason is that when PageContent component value change and Layout component rerender.

pageContent component wrap in memo() hook.

export default React.memo(PageContent);

and second, wrap handleScroll function in useMemo hook that returns memorize function.

    useMemo(function handleScroll() {
        const mainContent = pageContentRef.current;
        if (mainContent) {
            if (mainContent.scrollTop > 500) {
                setShowBackToTopButton(true);
            } else {
                setShowBackToTopButton(false);
            }
        }
    }, [dependency]);
Sign up to request clarification or add additional context in comments.

Comments

0

I found the solution wrapping my PageContent component inside a memo

const PageContent = React.memo(({ pageContentRef }: PageContentProps) => {
    return (
        // ...
    );
});

Children are now rendered only once. Hope it can help ohter people 🙂

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.