It is an interesting hook called useSyncExternalStore
came from React 18. After I went through the doc, I had totally no idea about how to use it and why it works. Luckily, I got a task I thought I can use this hook, and meanwhile I traced the source code to understand useSyncExternalStore
implementation. In this article, I will explain how it works internally and show a demo which is differ from the doc.
useSyncExternalStore
source code#
Let us read this helper checkIfSnapshotChanged
first. It compares the return value of getSnapshot
with prevValue
, and return true if they are different.
1 | function checkIfSnapshotChanged<T>(inst: { |
Since we have checkIfSnapshotChanged
helper, we can now proceed to useSyncExternalStore
.
1 | function useSyncExternalStore<T>( |
On every render, it retrieves a getSnapshot
value (Line 32) and sets both value
and getSnapshot
into state. It’s important to note that they use forceUpdate
as the setter name. Subsequently, it forces a re-render by forceUpdate({ inst })
if checkIfSnapshotChanged
passed (line 38, 45, and 50).
Continuing further, in the useEffect
, it returns a clean-up function by invoking subscribe
with a handleStoreChange
callback function (Line 56). Therefore, useSyncExternalStore
should pass a subscribe function with a type with (callback) => () => {}
.
useSyncExternalStore
demonstration#
According to the width, I have to generate many half circles on the top of menu card. Thus I use useSyncExternalStore
hook, listen resize as subscribe, and calculate the count depends on getBoundingClientRect.
1 | function subscribe(callback) { |
Just try to resize codepen below.
Conclusion#
Without useSyncExternalStore
, I would need to use useEffect
and useState
. Now, I just need to use useSyncExternalStore
hook and subscribe to changes in getBoundingClientRect when window is resized. It is quite useful, isn’t it?