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...
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 🙂