Search code examples
reactjsrendering

How do we stop the re-rendering of A and B in React?


enter image description here

import React, { useState, useEffect, useCallback } from "react";

export const Root = () => {
  const [items, setItems] = useState(["A", "B"]);

  const _onClick = useCallback( item => {
    return () =>alert(item);
  },[]);
  return (
    <>
      <button onClick={() => setItems(["A", "B", "C"])}>Button</button>
      {items.map((item, index) => (
        <Item key={index} item={item} onClick={_onClick(item)} />
      ))}
    </>
  );
};

const Item = React.memo(({ item, onClick }) => {
  useEffect(() => {
    console.log("Item: ", item);
  });
  return <button onClick={onClick}>{item}</button>;
});

How do we stop the re-rendering of A and B? The result I want is to be a memo on the console when the button is pressed and "Item: C".


Solution

  • Because onClick of <Item/> is new every time it is rendered, it will cause A and B to re-render.

    You can use React.memo second parameter to check, for example:

    const Item = React.memo(({ item, onClick }) => {
        // ...
        return <button onClick={onClick}>{item}</button>;
    }, (prevProps, nextProps) => {
        console.log(Object.is(prevProps.onClick, nextProps.onClick)); // console: false
    });
    

    More see doc.


    In your code, _onClick(item) will return new callback every render.

    <Item key={index} item={item} onClick={_onClick(item)} />
    

    You can change _onClick to this:

    const _onClick = useCallback(item => alert(item), []);
    

    Next, pass _onClick to Item, and change how button's onClick is executed.

    <Item key={index} item={item} onClick={_onClick} />
    
    //...
    
    <button onClick={() => onClick(item)}>{item}</button>
    

    The full code is as follows:

    import React, { useCallback, useState } from 'react';
    
    export const Root = () => {
        const [items, setItems] = useState(['A', 'B']);
    
        const _onClick = useCallback(item => alert(item), []);
        return (
            <>
                <button onClick={() => setItems(['A', 'B', 'C'])}>Button</button>
                {items.map((item, index) => (
                    <Item key={index} item={item} onClick={_onClick} />
                ))}
            </>
        );
    };
    
    const Item = React.memo(({ item, onClick }) => {
        useEffect(() => {
            console.log("Item: ", item);
        });
        return <button onClick={() => onClick(item)}>{item}</button>;
    });