javascriptreactjsmemo

How do I apply React.memo to all components in an array?


Is it possible to apply React.memo to an array of components with a for loop?
Say I have the following three components:

const Item1 = (props) => {
    const { index } = props;
    return (
        <div>{index}</div>
        );      
}

const Item2 = (props) => {
    const { index } = props;
    return (
        <div>{index}</div>
        );      
}

const Item3 = (props) => {
    const { index } = props;
    return (
        <div>{index}</div>
        );      
}

Could I do this in my App component?

const App = (props) => {
    const items = [Item1, Item2, Item3];
    let itemarray = [];
    let index = 0;
    for (const item of items) {
        const MemoizedItem = React.memo(item);
        itemarray.push(<MemoizedItem key={index} index={index} />);
        index++;
    }
    return (
        <div>
            {itemarray}
        </div>
        );
}

I know I can hard code React.memo for each of the three items (see below), but I'd like to be able to do it iteratively.

const Item1 = React.memo((props) => {
    const { index } = props;
    return (
        <div>{index}</div>
        );      
});

//...same for Item2 and Item3

Solution

  • Calling React.memo in the middle of rendering is a bad idea. It will have the exact opposite effect of the intended goal. Instead of being able to skip rendering, you will force it to do extra rendering.

    When you call React.memo and pass in a component, what's returned is a new type of component. Not a new instance, a new type. The main way react tells what has changed from one render to the next is by comparing the types on components. If the type changed, it's assumed to be different, and therefore the old component is unmounted and the new one is remounted. Every time App renders, it creates brand new types of component, which means nothing can be saved from one render to the next.

    I'd recommend just using React.Memo where you implement Item1, Item2, Item3. Eg:

    const Item1 = React.memo((props) => {
      const { index } = props;
      return (
        <div>{index}</div>
      );      
    })
    

    But if you absolutely need to do it dynamically, then you'll need to make sure you only do it once, which basically means you need to memoize the memoization:

    const App = (props) => {
      const items = [Item1, Item2, Item3];
      const memoizedItems = useMemo(() => {
        return items.map(item => React.Memo(item));
      }, [])
    
      let itemarray = [];
      let index = 0;
      for (const MemoizedItem of memoizedItems) {
        itemarray.push(<MemoizedItem key={index} index={index} />);
        index++;
      }
      return (
        <div>
          {itemarray}
        </div>
      );
    }