- vừa được xem lúc

useSyncExternalStore – Hook bị đánh giá thấp của React

0 0 2

Người đăng: Tiến Minh

Theo Viblo Asia

Bạn có thể đã nghe về useSyncExternalStore() chưa, đây là một hook mới trong React 18 để đăng ký theo dõi các nguồn dữ liệu bên ngoài. Nó thường được sử dụng nội bộ bởi các thư viện quản lý trạng thái – như Redux – để triển khai hệ thống selector.

Trong bài viết tương tác này, mình muốn đưa ra một vấn đề: các hook React trả về dư thừa gây ra những lần re-render không cần thiết. Chúng ta sẽ cùng xem cách useSyncExternalStore() có thể là một giải pháp hợp lý. image.png

Hook trả về dư thừa

Hãy cùng minh họa vấn đề với useLocation() từ React-Router.

Hook này trả về một object với nhiều thuộc tính (pathname, hash, search...), nhưng bạn có thể không sử dụng hết tất cả. Chỉ cần gọi hook này thôi cũng sẽ kích hoạt re-render mỗi khi bất kỳ thuộc tính nào trong số đó được cập nhật.

Hãy xem xét ví dụ ứng dụng sau:

function CurrentPathname() { const { pathname } = useLocation(); return <div>{pathname}</div>;
} function CurrentHash() { const { hash } = useLocation(); return <div>{hash}</div>;
} function Links() { return ( <div> <Link to="#link1">#link1</Link> <Link to="#link2">#link2</Link> <Link to="#link3">#link3</Link> </div> );
} function App() { return ( <div> <CurrentPathname /> <CurrentHash /> <Links /> </div> );
}

Mỗi khi bạn click vào một đường dẫn có hash, CurrentPathname sẽ bị re-render, dù nó chẳng hề sử dụng thuộc tính hash

Dùng useSyncExternalStore để cứu nguy?

Tài liệu chính thức nói rằng:

useSyncExternalStore là một hook được khuyến nghị để đọc và đăng ký theo dõi dữ liệu từ các nguồn bên ngoài theo cách tương thích với các tính năng kết xuất đồng thời như hydration chọn lọc và time slicing. Phương thức này trả về giá trị của store và chấp nhận ba đối số:

  • subscribe: hàm đăng ký một callback sẽ được gọi mỗi khi store thay đổi.
  • getSnapshot: hàm trả về giá trị hiện tại của store.
  • getServerSnapshot: hàm trả về snapshot được sử dụng trong quá trình kết xuất trên server.
function useSyncExternalStore<Snapshot>( subscribe: (onStoreChange: () => void) => () => void, getSnapshot: () => Snapshot, getServerSnapshot?: () => Snapshot,
): Snapshot;

Cảm giác hơi trừu tượng phải không? Trang tài liệu beta này đưa ra một ví dụ khá tốt:

function subscribe(callback) { window.addEventListener("online", callback); window.addEventListener("offline", callback); return () => { window.removeEventListener("online", callback); window.removeEventListener("offline", callback); };
} function useOnlineStatus() { return useSyncExternalStore( subscribe, () => navigator.onLine, () => true, );
} function ChatIndicator() { const isOnline = useOnlineStatus(); // ...
}

Hóa ra, lịch sử trình duyệt cũng có thể được coi là một nguồn dữ liệu bên ngoài. Hãy cùng xem cách sử dụng useSyncExternalStore với React-Router nhé!

UseHistorySelector()

React-Router đã cung cấp tất cả những gì chúng ta cần để kết nối với useSyncExternalStore:

  • Truy cập lịch sử trình duyệt với useHistory(): Hook này giúp bạn lấy được đối tượng history để thao tác với lịch sử.
  • Đăng ký lắng nghe các cập nhật lịch sử với history.listen(callback): Hàm này cho phép bạn đăng ký một callback để nhận thông báo mỗi khi có thay đổi trong lịch sử trình duyệt.
  • Truy cập snapshot của vị trí hiện tại với history.location: Thuộc tính này trả về thông tin về URL hiện tại trong trình duyệt.

Cách dùng useHistory() rất đơn giản:

function useHistorySelector(selector) { const history = useHistory(); return useSyncExternalStore(history.listen, () => selector(history), );
}

Hãy dùng cho app của bạn như sau:

function CurrentPathname() { const pathname = useHistorySelector( (history) => history.location.pathname, ); return <div>{pathname}</div>;
} function CurrentHash() { const hash = useHistorySelector( (history) => history.location.hash, ); return <div>{hash}</div>;
}

Giờ đây, khi bạn nhấp vào một liên kết hash phía trên, component CurrentPathname sẽ không còn bị re-render nữa!

Kết luận

Mình hy vọng bài viết này đã thuyết phục bạn nhìn nhận lại useSyncExternalStore(). Mình cảm thấy hook này hiện tại chưa được sử dụng nhiều trong hệ sinh thái React, và xứng đáng nhận được sự chú ý hơn nữa. Có rất nhiều nguồn dữ liệu bên ngoài mà bạn có thể đăng ký theo dõi.

Nếu bạn vẫn chưa nâng cấp lên React 18, hiện tại bạn có thể sử dụng một shim use-sync-external-store cho các phiên bản cũ hơn. Ngoài ra, cũng có một export use-sync-external-store/with-selector trong trường hợp bạn cần trả về một giá trị không phải nguyên thủy và đã memoized.

Bình luận

Bài viết tương tự

- vừa được xem lúc

[Frontend] 1 số note cơ bản về React Hook

Đây là 1 số note cơ bản về Reactjs Hook mình đang học, những kiến thức cản bản thui nhưng hy vọng sẽ giúp ích gì đó cho mọi người. Có gì mới thì mình sẽ update vào bài này luôn, có những chỗ sai sót ý

0 0 149

- vừa được xem lúc

Những điều cần lưu ý và sử dụng Hook trong React (Phần 5)

V. Sử dụng useRef như thế nào cho đúng.

0 0 146

- vừa được xem lúc

Sổ tay React Hooks cho mọi người?

Hế lô các bạn,. Lại là mình đây, dạo này code React nhiều quá đâm ra mình muốn viết 1 bài nào đó về React Thế mà nghĩ đi nghĩ lại, mình vấn quyết định viết về Hooks.

0 0 207

- vừa được xem lúc

ReactJS: So sánh cách viết logic để sử dụng lại giữa HOCs vs. Render Props vs. Hooks

Trong React, chúng ta có thể sử dụng Higher-Order Components và Render Props để viết một số logic và sử dụng lại cho nhiều component khác nhau. Thật lý tưởng nếu bạn viết mới tất cả component của bạn

0 0 50

- vừa được xem lúc

6 trường hợp sử dụng của useEffect() trong React

Hello anh em, chắc khi làm việc với ReactJs thì chúng ta cũng đã làm quen với việc sử dụng các hooks của nó rồi phải không, vậy thì hôm nay mình sẽ cùng anh em biết và đã biết tìm hiểu lại một chút về

0 0 201

- vừa được xem lúc

Tôi học Reactjs như thế nào phần 1 ? Làm mini-app Todo list

Chào các bạn mình là Kiệt , nếu các bạn thấy được bài viết này , thì cảm ơn bạn vì đã tốn thời gian để đọc bài viết này của mình. .

0 0 32