I've built a tabs component. Each tab, when clicked, changes the contents of the "main screen". Assume a tab had some back-end call to retrieve data it needs to render, then it makes no sense to have it re-run these calls every time the user clicks another tab and comes back to it. I want to retrieve what was rendered before and display it.
I looked into memo, the big warning says to "not rely on it to “prevent” a render, as this can lead to bugs.", nor does it work. Every time I wrap my component in a memo, the test:
useEffect(() => {
console.log('Rendered');
}, [])
Still runs, telling me that the component re-rendered. Then I thought about memoizing the return itself, so, like:
export const MyComponent = (context) => {
const content = useMemo(() => {
return <></>
}, [context]);
return content;
};
But quickly realized that by the time I reach this useMemo, I'm already in the re-rendering cycle, because there's no way for React to know that MyComponent's useMemo existed in the past, so, again, it re-renders the whole thing. This, in turn made me think that the memoization needs to be done at the level where MyComponent is being rendered, not inside of it but I don't know how to do it.
How can I skip re-renders if my props haven't changed?
Read all the articles, tried all the things but to no avail.
Concisely, here is my component and my latest approach:
export const MyComponent = memo(({ context, className = '', ...props }) => {
..
..
});
The interesting bit here is context. This should almost never change. Its structure is a deeply nested object, however, when I play with memo's second argument, its diff function, what ends up happening if I put a console.log in there, as follows:
const MyComponent = ({ context, className = '', ...props }) => {
};
const areEqual = (prevProps, nextProps) => {
console.log('Did equality check.');
};
export default memo(MyComponent, areEqual);
I will only see "Did equality check." once. No matter what I do, I can't seem to get a memoized component out of memo. This is how MyComponent's parent looks like:
const Parent = ({}) => {
const context = useSelector(); //context comes from the store.
const [selectedTab, setSelectedTab] = useState(false);
const [content, setContent] = useState(null);
useEffect(() => {
switch (selectedTab) {
case 'components':
setContent(<MyComponent context={context} />);
break;
}
}, [selectedTab, context]);
return(<>{content}</>);
};