I am passing functions to my child component. And I am using React.memo to restrict compoenent from re-rendering. But My component rerenders when parent re-renders. I tried to check why this is happening by using useEffect on all the props and I get to this point that my functions are causing compoenent to re-renders.
// my functions
const scrollToView = (index) => {
if (scrollRef && scrollRef.current && scrollRef.current[index]) {
scrollRef.current[index].scrollIntoView({ behavior: 'smooth' });
}
};
const scrollToReportView = (reportIndex) => {
if (scrollToReportRef && scrollToReportRef.current &&
scrollToReportRef.current[reportIndex]) {
scrollToReportRef.current[reportIndex].scrollIntoView({
behavior: 'smooth' });
}
}
.......
function LeftNav({
scrollToView, //function
scrollToReportView, //function
reports, //object
}) {
useEffect(() => {
console.log('scrollToView')
}, [scrollToView])
useEffect(() => {
console.log('scrollToReportView')
}, [scrollToReportView])
useEffect(() => {
console.log('reports')
}, [reports])
return (
<div>{'My Child Component'}</div>
);
}
export default memo(LeftNav);
And this is how my left nav is being called
<LeftNav
scrollToView={(index) => scrollToView(index)}
scrollToReportView={(repIndex)=> scrollToReportView(repIndex)}
reports={reports}
/>
With
<LeftNav
scrollToView={(index) => scrollToView(index)}
scrollToReportView={(repIndex)=> scrollToReportView(repIndex)}
reports={reports}
/>
you're creating new anonymous functions every time you render the LeftNav
component, so memoization does absolutely nothing.
Just
<LeftNav
scrollToView={scrollToView}
scrollToReportView={scrollToReportView}
reports={reports}
/>
instead (assuming those functions are stable by identity (e.g. are declared outside the component or are properly React.useCallback
ed or React.useMemo
ed).
In other words, if your component is currently
function Component() {
// ...
const scrollToView = (index) => {
if (scrollRef && scrollRef.current && scrollRef.current[index]) {
scrollRef.current[index].scrollIntoView({ behavior: "smooth" });
}
};
const scrollToReportView = (reportIndex) => {
if (scrollToReportRef && scrollToReportRef.current && scrollToReportRef.current[reportIndex]) {
scrollToReportRef.current[reportIndex].scrollIntoView({
behavior: "smooth",
});
}
};
return (
<LeftNav
scrollToView={(index) => scrollToView(index)}
scrollToReportView={(repIndex) => scrollToReportView(repIndex)}
reports={reports}
/>,
);
}
it needs to be something like
function Component() {
// ...
const scrollToView = React.useCallback((index) => {
if (scrollRef?.current?.[index]) {
scrollRef.current[index].scrollIntoView({ behavior: "smooth" });
}
}, []);
const scrollToReportView = React.useCallback((reportIndex) => {
if (scrollToReportRef?.current?.[reportIndex]) {
scrollToReportRef.current[reportIndex].scrollIntoView({
behavior: "smooth",
});
}
}, []);
return (<LeftNav scrollToView={scrollToView} scrollToReportView={scrollToReportView} reports={reports} />);
}
so the scrollToView
and scrollToReportView
functions have stable identities.