Đang trong những ngày “after GAP” thì tình trạng hiện tại của mình chính xác là thất nghiệp vì chưa tìm được công việc phù hợp với bản thân nên vừa học lại, vừa chia sẻ một số kĩ năng đã biết cho mọi người cũng như một cách để hệ thống hoá lại kiến thức của bạn thân.

Và series này là series [Hooks ký sự], mình sẽ lần lượt trình bày các hook của react.js😏

useMemo(fn, deps)

Khái niệm

Returns a memoized value.

Khái niệm của useMemo rất đơn giản đúng không nào, tham số thứ nhất là một func và tham số thứ hai là mảng chứa các dependencies và nó sẽ trả về giá trị đã được ghi nhớ (là kết quả trả về từ việc chạy hàm fn mà bạn truyền vào ứng với tham số).

Chức năng

useMemo chủ yếu được sử dụng để giải quyết các bài toán với nhiều logic nặng để tránh lặp lại các giá trị cũ.

“Nếu một trong số các dependencies thay đổi, thì hàm tính toán sẽ được thực thi lại, từ đó trả ra giá trị mới. Ngược lại, nếu nhận thấy giá trị của các dependencies kia không đổi, thì ngay lập tức useMemo trả ra kết quả trước đó mà không hề tính toán lại, từ đó tránh được một khối lượng lớn công việc, giúp ích cho performance.”

Ví dụ

Tưởng tượng bạn có function troll như bên dưới, chức năng của troll là mỗi khi count thay đổi thì mọi thứ sẽ được for đến chết… Tốc độ thì mình xin hứa với đảng là mỗi khi count change sẽ khiến máy đứng hình một vài giây 😂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { useState } from "react";

export default function App() {
const [count, setCount] = useState(0);
const [randomID, setRandomID] = useState();
const troll = (_count) => {
let _result = 0;
for (let _i = 0; _i < _count * 500000000; _i++) {
_result += _i;
}
return _result;
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<div>count: {count}</div>
<button onClick={() => setRandomID(Math.round(Math.random() * 10))}>
random
</button>
<div>randomID: {randomID}</div>
<div>troll: {troll(count)}</div>
</div>
);
}

Và nhìn hình bạn sẽ thấy, dù count không thay đổi nhưng khi mình random thì mọi thứ trở nên thật kinh dị, mình chỉ muốn lấy kết quả random nhưng lúc re-render thì lại phải tính toán lại đống troll của mình 😂

https://s8.gifyu.com/images/CPT2206191140-453x214.gif

Và mình chắc chắn bạn cũng như mình, sẽ không thích điều này… Từ đó chắc chắn mình sẽ cần tới memo😏😏 Code được viết đơn giản lại thành như thế này

1
2
3
4
5
6
7
8
const troll = (_count) => {
let _result = 0;
for (let _i = 0; _i < _count * 500000000; _i++) {
_result += _i;
}
return _result;
};
const trollWithMemo = useMemo(() => troll(count), [count]);

https://s8.gifyu.com/images/CPT2206191143-453x214.gif

Và nhìn hình bạn sẽ thấy, phép màu đã xuất hiện 😂 Và tới đây chắc bạn cũng đã hiểu sơ sơ về useMemo rồi đúng không (Hoặc nếu bạn không hiểu thì kệ bạn 😂 😂

Hì hì, ngoài ra dựa vào việc không phải tính toán lại cũng tránh được trường hợp function này sẽ thay đổi hoặc tạo ra một cái gì đó không thú dị 😂

Một chút về React.Memo

Đơn giản là React.Memo ra để giải quyết các vấn đề liên quan đến re-render vô tội vạ, giải quyết vấn đề như PureComponent hoặc shouldComponentUpdate ở class component thôi. Chức năng của nó là kiểm tra nông xem props có thay đổi hay không, nếu như không thay đổi thì không cần re-render làm gì cho mất công. Phạm vi bài viết này mình chỉ muốn nhắc tới thôi, thật ra useMemo thì lấy lại kết quả cũ nếu tham số đầu vào không thay đổi còn React.me thì sẽ lấy lại component đã render cũ nếu props không thay đổi.

useCallback(fn, deps)

Khái niệm

useCallback thì tập trung giải quyết vấn đề về performance, khi mà các callback function được tạo ở functional component cha pass xuống component con luôn bị tạo mới, khiến cho con luôn bị re-render.

Chức năng

Nhưng khác với useMemo thì useCallback lại trả về một function, và function này sẽ chỉ được tạo lại khi một trong số các dependencies thay đổi. Nếu dependencies không đổi, function trả về sẽ là function trước đó -> tức là function pass xuống component con không bị tạo mới, tương đương không có object được tạo mới -> component con không bị re-render.

Ví dụ

Tương tự ví dụ trên và chúng ta có tốc độ load siêu khủng khiếp 😂

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import { useState, memo } from "react";

const Troll = memo(({ count, updateCount }) => {
const troll = (_count) => {
let _result = 0;
for (let _i = 0; _i < _count * 500000000; _i++) {
_result += _i;
}
return _result;
};
return (
<>
<button onClick={() => updateCount()}>+</button>
<div>count: {count}</div>
<div>troll: {troll(count)}</div>
</>
);
});

export default function App() {
const [count, setCount] = useState(0);
const [randomID, setRandomID] = useState();
const updateCount = () => setCount(count + 1);

return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<Troll count={count} updateCount={(updateCount)} />
<button onClick={() => setRandomID(Math.round(Math.random() * 10))}>
random
</button>
<div>randomID: {randomID}</div>
</div>
);
}

Và vẫn như cũ, khi chúng ta random number thì function updateCount lại được tạo mới và pass xuống Troll, nên dù mình đã dùng React.memo nhưng mọi thứ vẫn chậm như hình:

https://s8.gifyu.com/images/CPT2206191722-786x214.gif

Và với một thao tác viết lại function useCallback đơn giản như sau:

1
2
3
const updateCount = useCallback(() => {
setCount(count + 1);
}, [count])

tốc độ đã được cải thiện đáng kể khi chúng ta không đụng đến count:

https://s8.gifyu.com/images/CPT2206191726-786x214.gif

Chỉ với một vài thao tác đơn giản, chúng ta đã biến tốc độ của một cái app siêu chậm đã nhanh hơn một tẹo nào đó😏

So sánh giữa useMemo vs useCallback

useMemo và useCallback đề dùng để "returns a memoized value", nhưng value return của useMemo và một giá trị cụ thể tuỳ vào function và biến đầu vào còn với useCallback là một function nếu như tham số deps không thay đổi.

À, có một tips nhỏ khá thú vị là useMemo sẽ return giá trị, và giá trị này có thể là function nếu như bạn muốn:

1
useCallback(fn, deps) = useMemo(() => fn, deps)

Kết luận

Vậy là chúng ta đã qua 2 hook thường đường sử dụng khi chúng ta làm việc với react function component rồi đúng không, hy vọng chuỗi series này sẽ được update đến phần sau nếu như mình nhận được bất cứ yêu cầu nào.

Dạo này mình đang thất nghiệp nên đang thực hiện vài dự án cá nhân, làm một vài dự án ngoài và còn khá nhiều thời gian rảnh nên mình sẽ tập trung viết.