useCallback 依赖数组在更新数组时破坏了防止 re-renders 的目的
useCallback dependency array defeats the purpose of preventing re-renders when updating an array
以下 React 应用程序显示水果列表。每个 Fruit
都有一个“添加到收藏夹”按钮,该按钮使用 addFav
回调将所述水果添加到 parent 中的收藏夹列表。传入 handleAddFav
回调会导致不必要的 re-renders,所以我将其包装在 useCallback
和 Fruit
中的 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
被传递下来,即使它依赖于num
,useCallback
仍然会在只有[的情况下阻止child re-renders =17=] 发生变化,num
保持不变。
以下 React 应用程序显示水果列表。每个 Fruit
都有一个“添加到收藏夹”按钮,该按钮使用 addFav
回调将所述水果添加到 parent 中的收藏夹列表。传入 handleAddFav
回调会导致不必要的 re-renders,所以我将其包装在 useCallback
和 Fruit
中的 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
被传递下来,即使它依赖于num
,useCallback
仍然会在只有[的情况下阻止child re-renders =17=] 发生变化,num
保持不变。