useCallback 依赖数组在更新数组时破坏了防止 re-renders 的目的

useCallback dependency array defeats the purpose of preventing re-renders when updating an array

以下 React 应用程序显示水果列表。每个 Fruit 都有一个“添加到收藏夹”按钮,该按钮使用 addFav 回调将所述水果添加到 parent 中的收藏夹列表。传入 handleAddFav 回调会导致不必要的 re-renders,所以我将其包装在 useCallbackFruit 中的 memo.

然而,useCallback 要求在其依赖数组中包含 favs,这导致 handleAddFav 每次被调用时都是 re-computed。这违背了使用 useCallback 停止 re-renders 的目的,因为现在每次添加收藏夹时每个 Fruit re-renders。我该如何解决?

import { useState, memo, useCallback } from "react";
import "./styles.css";

const Fruit = memo(({title, id, addFav}) => {
  console.log(title, 'rendered')
  return (
    <div>
      <div>{title}</div>
      <button onClick={() => addFav(title, id)}>add fav</button>
    </div>
  )
})

export default function App() {
  const [favs, setFavs] = useState([])
  const data = [{title: 'apple', id: '1'}, {title:'orange', id:'2'}
  , {title:'banana', id:'3'}]

  const handleAddFav = useCallback((title, id) => {
    setFavs([...favs, {title, id}])
  }, [favs])
  return (
    <div className="App">
      <h1>Testing useCallback that sets an array</h1>
      <h2>Favorites</h2>
      <button onClick={() => setFavs([])}>clear</button>
      {
        favs.map(({title, id}, i) => <span key={id + i}>{title}</span>)
      }
      {
        data.map(({title, id }) => (
          <Fruit key={id} title={title} id={id} addFav={handleAddFav}/>
        ))
      }
    </div>
  );
}

一种方法是使用 setFavs 的函数版本,因此它不依赖于外部变量。

const handleAddFav = useCallback((title, id) => {
  setFavs(favs => [...favs, {title, id}])
}, [])

对于更一般的情况——即使你确实有一个必须是 re-computed 的值,使用 useCallback 仍然可以减少 re-renders 的情况 [=25] =]other 组件中的值发生变化,但计算值不变。例如

const TheComponent = () => {
  const [toggled, setToggled] = useState(false);
  const [num, setNum] = useState(5);
  const cb = useCallback(() => {
    // imagine that this does something that depends on num
  }, [num]);

如果cb被传递下来,即使它依赖于numuseCallback仍然会在只有[的情况下阻止child re-renders =17=] 发生变化,num 保持不变。