How does one cache an entire functional component in React?

Viewed 1570

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}</>);
};
0 Answers
Related