0

I'm not deep understanding how memo works with the component. I have component like this. It is very simple and it is static.

const Home = memo((props: any) => {     
  useEffect(() => {
    console.log('home changed');
  }, [])   
  return (
    <>
    <h1>This is homepage</h1>
    </>
  )  
})

I has route is /home. Everytime I come to Homepage route, I always got message with log home change. So this component is not cached with memo? If it was cached, how to realize the Component is not re-rendered?

Hai Tien
  • 2,929
  • 7
  • 36
  • 55
  • Are you routing away from home, then routing back to it? If so, when you route back it will have to render once. `memo` skips rendering if an already-mounted component doesn't change its props, but you still need to render once to mount it. – Nicholas Tower Mar 12 '23 at 19:54
  • @NicholasTower Yes, that is right. When the route back it will be render once. So which actually cached with memo and is it neccessary? Actually, in big project we have many props, each props have many functions inside. Example: Input onChange always change props, so we have to add useMemo for each action like this? – Hai Tien Mar 12 '23 at 19:59

1 Answers1

1

memo can't stop the very first render which happens when mounting a component. That render must always take place. So if you route away from the home page you unmount it, and when you route back you must re-mount it, resulting in one render

Instead what memo does is potentially skip later renders. Every time the component would re-render due to a change in props, react will first do a shallow comparison of all the props. If none of them changed, it skips rendering and uses what your component returned last time.

Actually, in big project we have many props, each props have many functions inside. Example: Input onChange always change props, so we have to add useMemo for each action like this?

In order for memo to work, the props need to stay the same, so you will need to make sure you're not changing props. Functions are indeed one case you need to be careful of, because if you're making a brand new function every time you render and then passing that to a child component, the child is constantly having its memoization broken. The fix for this is typically to wrap your function in useCallback so you use the same instance of the function on each render. For example:

const Parent = () => {
  // This log will happen when mounting, plus every time the count state changes
  console.log('rendering parent');

  const [count, setCount] = useState(1);
  useEffect(() => {
    const id = setInterval(() => {
      setCount(prev => prev + 1);
    }, 1000);
    return () => { clearInterval(id); };
  }, []);
  
  // Without the useCallback, we would be making a new onChange with every render of
  //   Parent. With useCallback, we keep reusing the function from the first render
  const onChange = useCallback((event) => {
    // Do something
  }, []);  

  return (
    <div>
      Count: {count}
      <Child onChange={onChange} />
    </div>
}


const Child = memo(({ onChange }) => {
  // This log will only happen when mounting, plus when onChange changes. And thanks
  //   to useCallback, onChange will not change.
  console.log('rendering child');
  return (
    <input onChange={onChange}/>
  )
})
Nicholas Tower
  • 72,740
  • 7
  • 86
  • 98
  • Thank for your great answer but do you know how many levels of Memo cached for each props change. Example in history of props: - Current Prop: ABC - History 1: XZY - History 2: BCD - History 3: ABC Is it cached to History 3? – Hai Tien Mar 12 '23 at 20:25
  • 1
    Just 1 level. It's comparing the props on the current render with the props on the previous render. Further back in time is not cached. – Nicholas Tower Mar 12 '23 at 22:00