React w/hooks:防止重新渲染具有函数作为 prop 的组件
React w/hooks: prevent re-rendering component with a function as prop
假设我有:
const AddItemButton = React.memo(({ onClick }) => {
// Goal is to make sure this gets printed only once
console.error('Button Rendered!');
return <button onClick={onClick}>Add Item</button>;
});
const App = () => {
const [items, setItems] = useState([]);
const addItem = () => {
setItems(items.concat(Math.random()));
}
return (
<div>
<AddItemButton onClick={addItem} />
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
</div>
);
};
每当我添加一个项目时,<AddItemButton />
都会重新呈现,因为 addItem 是一个新实例。我尝试记忆 addItem:
const addItemMemoized = React.memo(() => addItem, [setItems])
但这是重用第一个渲染中的 setItems,而
const addItemMemoized = React.memo(() => addItem, [items])
自从 items
引用发生变化后不记忆。
我做不到
const addItem = () => {
items.push(Math.random());
setItems(items);
}
因为这不会更改 items
的引用,也不会更新任何内容。
一种奇怪的方法是:
const [, frobState] = useState();
const addItemMemoized = useMemo(() => () => {
items.push(Math.random());
frobState(Symbol())
}, [items]);
但我想知道是否有更好的方法不需要额外的状态引用。
当前的首选路线是useCallback
,这与您的useMemo
解决方案相同,但将来可能会进行其他优化。传递一个空数组 []
以确保该函数 始终 在组件的生命周期内具有相同的引用。
在这里,您还想使用 functional state update form,以确保始终根据当前状态添加项目。
const addItem = useCallback(() => {
setItems(items => [...items, Math.random()]);
}, []);
假设我有:
const AddItemButton = React.memo(({ onClick }) => {
// Goal is to make sure this gets printed only once
console.error('Button Rendered!');
return <button onClick={onClick}>Add Item</button>;
});
const App = () => {
const [items, setItems] = useState([]);
const addItem = () => {
setItems(items.concat(Math.random()));
}
return (
<div>
<AddItemButton onClick={addItem} />
<ul>
{items.map(item => <li key={item}>{item}</li>)}
</ul>
</div>
);
};
每当我添加一个项目时,<AddItemButton />
都会重新呈现,因为 addItem 是一个新实例。我尝试记忆 addItem:
const addItemMemoized = React.memo(() => addItem, [setItems])
但这是重用第一个渲染中的 setItems,而
const addItemMemoized = React.memo(() => addItem, [items])
自从 items
引用发生变化后不记忆。
我做不到
const addItem = () => {
items.push(Math.random());
setItems(items);
}
因为这不会更改 items
的引用,也不会更新任何内容。
一种奇怪的方法是:
const [, frobState] = useState();
const addItemMemoized = useMemo(() => () => {
items.push(Math.random());
frobState(Symbol())
}, [items]);
但我想知道是否有更好的方法不需要额外的状态引用。
当前的首选路线是useCallback
,这与您的useMemo
解决方案相同,但将来可能会进行其他优化。传递一个空数组 []
以确保该函数 始终 在组件的生命周期内具有相同的引用。
在这里,您还想使用 functional state update form,以确保始终根据当前状态添加项目。
const addItem = useCallback(() => {
setItems(items => [...items, Math.random()]);
}, []);