Поскольку onClick
из <Item/>
является новым при каждом рендеринге, это приведет к повторному рендерингу A и B.
Вы можете использовать React.memo
второй параметр для проверки, например:
const Item = React.memo(({ item, onClick }) => {
// ...
return <button onClick={onClick}>{item}</button>;
}, (prevProps, nextProps) => {
console.log(Object.is(prevProps.onClick, nextProps.onClick)); // console: false
});
Подробнее см. do c.
В вашем коде _onClick(item)
будет возвращать новый обратный вызов при каждом рендере.
<Item key={index} item={item} onClick={_onClick(item)} />
Вы можете изменить _onClick
на следующее:
const _onClick = useCallback(item => alert(item), []);
Далее, передать _onClick для Item и изменить способ выполнения кнопки onClick.
<Item key={index} item={item} onClick={_onClick} />
//...
<button onClick={() => onClick(item)}>{item}</button>
Полный код выглядит следующим образом:
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>;
});