useCallback
HookReact useCallback
Hook 返回一个记忆的回调函数。
将记忆视为缓存一个值,以便不需要重新计算。
这使我们能够隔离资源密集型函数,以便它们不会在每个渲染上自动运行。
这个useCallback
Hook 仅在其依赖项之一更新时运行。
这可以提高性能。
这个useCallback
和useMemo
钩子是类似的。主要区别在于useMemo
返回一个记忆的值和useCallback
返回一个记忆的函数。您可以在 useMemo 中了解有关 useMemo 的更多信息章节。
使用理由之一useCallback
是为了防止组件重新渲染,除非它的 props 发生了变化。
在此示例中,您可能会认为Todos
组件不会重新渲染,除非todos
改变:
这是一个与 中的例子类似的例子React.memo部分。
index.js
import { useState } from "react";
import ReactDOM from "react-dom/client";
import Todos from "./Todos";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Todos.js
import { memo } from "react";
const Todos = ({ todos, addTodo }) => {
console.log("child render");
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</>
);
};
export default memo(Todos);
尝试运行它并单击计数增量按钮。
您会注意到Todos
即使组件重新渲染todos
不要换。
为什么这不起作用?我们正在使用memo
, 所以Todos
组件不应重新渲染,因为todos
国家也不addTodo
当计数增加时,函数会发生变化。
这是因为一种叫做"referential equality"的东西。
每次重新渲染组件时,都会重新创建其功能。正因为如此,addTodo
功能实际上已经改变了。
为了解决这个问题,我们可以使用useCallback
钩子以防止函数被重新创建,除非必要。
使用useCallback
挂钩以防止Todos
避免不必要地重新渲染组件:
index.js
import { useState, useCallback } from "react";
import ReactDOM from "react-dom/client";
import Todos from "./Todos";
const App = () => {
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const increment = () => {
setCount((c) => c + 1);
};
const addTodo = useCallback(() => {
setTodos((t) => [...t, "New Todo"]);
}, [todos]);
return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
Todos.js
import { memo } from "react";
const Todos = ({ todos, addTodo }) => {
console.log("child render");
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</>
);
};
export default memo(Todos);
现在Todos
组件只会在以下情况下重新渲染todos
道具变化。
截取页面反馈部分,让我们更快修复内容!也可以直接跳过填写反馈内容!