React useCallback
Hook
React useCallback
Hook trả về một hàm gọi lại đã ghi nhớ.
Hãy coi ghi nhớ như một giá trị lưu vào bộ nhớ đệm để nó không cần phải tính toán lại.
Điều này cho phép chúng tôi cô lập các chức năng sử dụng nhiều tài nguyên để chúng không tự động chạy trên mỗi lần hiển thị.
useCallback
Hook chỉ chạy khi một trong các phần phụ thuộc của nó cập nhật .
Điều này có thể cải thiện hiệu suất.
The useCallback
và useMemo
Hooks cũng tương tự như vậy. Sự khác biệt chính là useMemo
trả về một giá trị được ghi nhớ và useCallback
trả về một hàm được ghi nhớ . Bạn có thể tìm hiểu thêm về useMemo trong chương useMemo .
Vấn đề
Một lý do để sử dụng useCallback
là ngăn một thành phần hiển thị lại trừ khi các đạo cụ của nó đã thay đổi.
Trong ví dụ này, bạn có thể nghĩ rằng Todos
thành phần sẽ không hiển thị lại trừ khi todos
thay đổi:
Đây là một ví dụ tương tự với ví dụ trong phần React.memo .
Thí dụ:
index.js
import { useState } from "react";
import ReactDOM from "react-dom";
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>
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
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);
Hãy thử chạy cái này và nhấp vào nút tăng số lượng.
Bạn sẽ nhận thấy rằng Todos
thành phần hiển thị lại ngay cả khi todos
không thay đổi.
Tại sao cai nay không hoạt động? Chúng tôi đang sử dụng memo
, vì vậy Todos
thành phần không nên hiển thị lại vì cả todos
trạng thái và addTodo
hàm đều không thay đổi khi số lượng được tăng lên.
Điều này là do một thứ gọi là "bình đẳng tham chiếu".
Mỗi khi một thành phần hiển thị, các chức năng của nó sẽ được tạo lại. Bởi vì điều này, addTodo
chức năng đã thực sự thay đổi.
Được chứng nhận!
$ 95 GHI DANH
Giải pháp
Để khắc phục điều này, chúng ta có thể sử dụng useCallback
hook để ngăn hàm được tạo lại trừ khi cần thiết.
Sử dụng useCallback
Hook để ngăn Todos
thành phần hiển thị không cần thiết:
Thí dụ:
index.js
import { useState, useCallback } from "react";
import ReactDOM from "react-dom";
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>
</>
);
};
ReactDOM.render(<App />, document.getElementById('root'));
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);
Bây giờ Todos
thành phần sẽ chỉ hiển thị lại khi todos
prop thay đổi.