useEffect(() => {
// thực hiện side effect
return () => /* dọn rác */
}, [khai báo các giá trị mà nó phụ thuộc]);
useLayoutEffect(() => {
// thực hiện side effect
return () => /* dọn rác */
}, [thực hiện side effect]);
Nếu ko có khác nhau thì React team sẽ không tạo ra 2 thằng, hiển nhiên?. (Hầu như có thể dụng useEffect
trong mọi tình huống)
Khác nhau là ở THỜI GIAN THỰC HIỆN
useEffect
chạy bất tuần tự và đợi sau khi việc component đã xuất hiện trên màn hình (sau khi trình duyệt paint)
Quá trình cụ thế là thế này
- Component gọi đến
render
- Màn hình cập nhập lại UI mới
- SAU ĐÓ chạy
useEffect
useLayoutEffect
, ngược lại, chạy tuần tự sau khi render nhưng là trước khi UI cập nhập
Quá trình
- Component gọi đến
render
useLayoutEffect
được gọi, đợi chạy xong mới đi tiếp- Màn hình cập nhập lại UI mới
Trong 99% các trường hợp, sử dụng useEffect
sẽ là cách tốt nhất, vì những effect của chúng ta sẽ cần đồng bộ với prop, state, không cần xảy ra NGAY LẬP TỨC và không ảnh hưởng đến kết quả cuối cùng của UI.
Ví dụ như fetch dữ liệu sẽ không cần có kết quả ngay lập tức, hay đặt để các event handler
Nếu thấy UI bị flickering
(giống như xuất hiện sọc sọc trên màn hình tivi) khi cập nhập, nguyên nhân do nó đã render khi vừa có state, sau đó lại re-render lại với state nhận được sau cùng. Đó là lúc bạn dùng useLayoutEffect
Ví dụ nhé, bạn cho user click để thay đổi state value
, nó sẽ re-render component, sau đó effect chạy, nó lại set giá trị value
thành một con số ngẫu nhiên => lại re-render component.
import React, {
useState,
useLayoutEffect
} from 'react';
import ReactDOM from 'react-dom';
const BlinkyRender = () => {
const [value, setValue] = useState(0);
useLayoutEffect(() => {
if (value === 0) {
setValue(10 + Math.random() * 200);
}
}, [value]);
console.log('render', value);
return (
<button onClick={() => setValue(0)}>
value: {value}
</button >
);
};
ReactDOM.render(
<BlinkyRender />,
document.querySelector('#root')
);
Với cách dùng useLayoutEffect
chúng ta chỉ cập nhập UI đúng 1 lần, trong khi component gọi render 2 lần.
Initializing...