Trong phần 7 này, chúng ta sẽ tìm hiểu cách sử dụng hook useInsertionEffect
useInsertionEffect
useInsertionEffect dành cho tác giả thư viện CSS-in-JS. Trừ khi bạn đang làm việc trên thư viện CSS-in-JS và cần một nơi để chèn styles, thay vào đó bạn có thể muốn useEffect hoặc useLayoutEffect.
useInsertionEffect cho phép chèn các phần tử vào DOM trước khi kích hoạt bất kỳ layout Effects nào.
Cách sử dụng
useInsertionEffect(setup, dependencies?)
-
- setup:Hàm với logic Effect của bạn. Chức năng thiết lập của bạn cũng có thể tùy chọn trả về chức năng dọn dẹp. Khi component của bạn được thêm vào DOM, nhưng trước khi bất kỳ layout Effects nào kích hoạt, React sẽ chạy chức năng thiết lập của bạn. Sau mỗi lần re-render với dependencies đã thay đổi, trước tiên React sẽ chạy hàm dọn dẹp (nếu bạn cung cấp) với các giá trị cũ, sau đó chạy hàm thiết lập với các giá trị mới. Khi component của bạn bị xóa khỏi DOM, React sẽ chạy chức năng dọn dẹp của bạn.
- dependencies:Danh sách tất cả các giá trị phản ứng được tham chiếu bên trong code. Các giá trị phản ứng bao gồm props, state cũng như tất cả các biến và hàm được khai báo trực tiếp bên trong nội dung component của bạn. . Danh sách các phần phụ thuộc phải có số lượng mục không đổi và được viết nội tuyến như [dep1, dep2, dep3]. React sẽ so sánh từng phần phụ thuộc với giá trị trước đó bằng thuật toán so sánh Object.is. Nếu bạn hoàn toàn không chỉ định các phần phụ thuộc, Effect của bạn sẽ chạy lại sau mỗi lần render component của bạn.
Một vài điểm cần lưu ý:
-
- Effect chỉ chạy trên client. Chúng không chạy trong quá trình server rendering.
- Bạn không thể cập nhật state từ bên trong useInsertionEffect.
- Vào thời điểm useInsertionEffect chạy, các ref vẫn chưa được đính kèm.
- useInsertionEffect có thể chạy trước hoặc sau khi DOM được cập nhật. Bạn không nên dựa vào việc DOM được cập nhật vào bất kỳ thời điểm cụ thể nào.
- Không giống như các loại Effects khác, kích hoạt quá trình dọn dẹp cho Effects và sau đó thiết lập cho Effects, useInsertionEffect sẽ kích hoạt cả quá trình dọn dẹp và thiết lập từng component. Điều này dẫn đến sự “xen kẽ” giữa các chức năng dọn dẹp và thiết lập chức năng.
Hook này được sử dụng trong các trường hợp:
- Chèn tự động styles từ thư viện CSS-in JS
Ví dụ minh họa
Thông thường bạn sẽ style react components bằng css đơn giản
// In your JS file:
<button className="success" />
// In your CSS file:
.success { color: green; }
Một số nhóm thích styles trực tiếp bằng mã JavaScript thay vì viết file CSS. Điều này thường yêu cầu sử dụng thư viện CSS-in-JS hoặc một công cụ. Có ba cách tiếp cận phổ biến đối với CSS-in-JS:
- Trích xuất tĩnh sang file CSS bằng trình biên dịch
- Kiểu nội tuyến(Inline styles), ví dụ:
- Chèn thẻ
<style>
trong quá trình chạy.
Nếu bạn sử dụng CSS-in-JS, chúng tôi khuyên bạn nên kết hợp hai phương pháp đầu tiên (file CSS cho styles tĩnh, kiểu nội tuyến(Inline styles) cho styles động). Chúng tôi khuyên bạn không nên chèn thẻ thời gian chạy vì hai lý do:
– Tính năng chèn thời gian chạy buộc trình duyệt phải tính toán lại styles thường xuyên hơn rất nhiều.
– Tính năng chèn thời gian chạy có thể rất chậm nếu nó xảy ra không đúng lúc trong vòng đời React.
Vấn đề “trình duyệt phải tính toán lại styles” không thể giải quyết được nhưng useInsertionEffect sẽ giúp bạn giải quyết vấn đề thứ hai.
Gọi useInsertionEffect để chèn styles trước khi bất kỳ layout Effects nào kích hoạt:
// Inside your CSS-in-JS library
let isInserted = new Set();
function useCSS(rule) {
useInsertionEffect(() => {
// As explained earlier, we don't recommend runtime injection of <style> tags.
// But if you have to do it, then it's important to do in useInsertionEffect.
if (!isInserted.has(rule)) {
isInserted.add(rule);
document.head.appendChild(getStyleForRule(rule));
}
});
return rule;
}
function Button() {
const className = useCSS('...');
return <div className={className} />;
}
Tương tự như useEffect, useInsertionEffect không chạy trên server. Nếu bạn cần thu thập những rules CSS nào đã được sử dụng trên server, bạn có thể thực hiện việc đó trong quá trình render:
let collectedRulesSet = new Set();
function useCSS(rule) {
if (typeof window === 'undefined') {
collectedRulesSet.add(rule);
}
useInsertionEffect(() => {
// ...
});
return rule;
}