React 18 ਨੇ useSyncExternalStore ਜੋੜਿਆ ਹੈ, ਇੱਕ ਅਜਿਹਾ hook ਜੋ components ਨੂੰ React tree ਤੋਂ ਬਾਹਰ ਮੌਜੂਦ ਕਿਸੇ ਵੀ source ਤੋਂ data ਪੜ੍ਹਨ ਦੀ ਇਜਾਜ਼ਤ ਦਿੰਦਾ ਹੈ—ਜਿਵੇਂ ਕਿ browser APIs, WebSockets, ਜਾਂ third-party stores—ਉਨ੍ਹਾਂ visual glitches ਤੋਂ ਬਿਨਾਂ ਜੋ useState ਅਤੇ useEffect ਨਾਲ ਉਸ data ਨੂੰ mirror ਕਰਨ ਦੇ ਪੁਰਾਣੇ pattern ਵਿੱਚ ਹੁੰਦੇ ਸਨ। ਜੇਕਰ ਤੁਸੀਂ ਕਦੇ UI ਨੂੰ ਫਲਿੱਕਰ (flicker) ਕਰਦੇ ਹੋਏ ਦੇਖਿਆ ਹੈ ਕਿਉਂਕਿ ਉਸਦਾ ਇੱਕ ਹਿੱਸਾ ਪੁਰਾਣਾ window size ਦਿਖਾ ਰਿਹਾ ਸੀ ਜਦੋਂ ਕਿ ਦੂਜਾ ਹਿੱਸਾ ਪਹਿਲਾਂ ਹੀ ਨਵਾਂ size ਦਿਖਾ ਰਿਹਾ ਸੀ, ਤਾਂ ਇਹ hook ਉਸ ਸਮੱਸਿਆ ਦਾ ਹੱਲ ਹੈ ਜਿਸਦਾ ਤੁਸੀਂ ਇੰਤਜ਼ਾਰ ਕਰ ਰਹੇ ਸੀ।
ਬਾਹਰੀ state ਲਈ ਨਵੇਂ hook ਦੀ ਲੋੜ ਕਿਉਂ ਹੈ
React components ਹਮੇਸ਼ਾ ਤੋਂ ਉਨ੍ਹਾਂ ਚੀਜ਼ਾਂ ਨੂੰ subscribe ਕਰਨ ਦੇ ਯੋਗ ਰਹੇ ਹਨ ਜੋ ਉਹਨਾਂ ਦੇ ਆਪਣੇ scope ਤੋਂ ਬਾਹਰ ਮੌਜੂਦ ਹਨ: ਜਿਵੇਂ ਕਿ window object, ਇੱਕ Redux store, ਜਾਂ ਇੱਕ WebSocket connection। ਰਵਾਇਤੀ ਤਰੀਕਾ useEffect ਦੇ ਅੰਦਰ ਇੱਕ subscription ਸੈੱਟ ਕਰਨਾ, setState ਰਾਹੀਂ ਆਉਣ ਵਾਲੀਆਂ values ਨੂੰ local state ਵਿੱਚ ਪਾਉਣਾ, ਅਤੇ React ਨੂੰ re-render ਕਰਨ ਦੇਣਾ ਸੀ। ਇਹ ਉਦੋਂ ਠੀਕ ਕੰਮ ਕਰਦਾ ਹੈ ਜਦੋਂ React synchronously render ਕਰਦਾ ਹੈ, ਪਰ React 18 ਨੇ concurrent rendering ਦੀ ਸ਼ੁਰੂਆਤ ਕੀਤੀ ਹੈ, ਜਿੱਥੇ ਇੱਕ component browser ਦੁਆਰਾ ਅਸਲ ਵਿੱਚ paint ਕੀਤੇ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਕਈ ਵਾਰ render ਹੋ ਸਕਦਾ ਹੈ। ਉਸ mode ਵਿੱਚ “mirror-into-local-state” pattern tearing ਪੈਦਾ ਕਰ ਸਕਦਾ ਹੈ—ਜਿਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਇੱਕ ਸਿੰਗਲ render cycle ਦੌਰਾਨ UI ਦੇ ਵੱਖ-ਵੱਖ ਹਿੱਸੇ ਇੱਕੋ external value ਦੇ ਵੱਖ-ਵੱਖ snapshots ਪੜ੍ਹ ਰਹੇ ਹੁੰਦੇ ਹਨ।
useSyncExternalStore ਨੂੰ tearing ਨੂੰ ਰੋਕਣ ਲਈ ਬਣਾਇਆ ਗਿਆ ਸੀ। ਇਹ external source ਤੋਂ ਇੱਕ snapshot (ਮੌਜੂਦਾ value) ਅਤੇ ਇੱਕ subscribe function (ਬਦਲਾਅ ਬਾਰੇ ਸੂਚਿਤ ਹੋਣ ਦਾ ਤਰੀਕਾ) ਮੰਗਦਾ ਹੈ। ਜਦੋਂ component mount ਹੁੰਦਾ ਹੈ ਤਾਂ React subscribe ਨੂੰ ਕਾਲ ਕਰਦਾ ਹੈ ਅਤੇ unmount ਹੋਣ 'ਤੇ ਆਪਣੇ ਆਪ unsubscribe ਕਰ ਦਿੰਦਾ ਹੈ। ਜਦੋਂ ਵੀ getSnapshot ਦੁਆਰਾ ਵਾਪਸ ਕੀਤਾ ਗਿਆ snapshot ਬਦਲਦਾ ਹੈ, React ਇੱਕ ਅਜਿਹਾ render schedule ਕਰਦਾ ਹੈ ਜੋ ਪੂਰੇ component tree ਲਈ ਉਹੀ snapshot ਪੜ੍ਹਦਾ ਹੈ, ਜਿਸ ਨਾਲ consistency ਯਕੀਨੀ ਬਣਦੀ ਹੈ।
ਦੋ ਲੋੜੀਂਦੇ functions
| Function | ਇਹ ਕੀ ਕਰਦਾ ਹੈ |
|---|---|
| subscribe | ਇੱਕ callback ਪ੍ਰਾਪਤ ਕਰਦਾ ਹੈ ਜਿਸ ਨੂੰ ਉਦੋਂ ਕਾਲ ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਹੈ ਜਦੋਂ ਵੀ external value ਬਦਲਦੀ ਹੈ। ਇਹ ਇੱਕ unsubscribe function ਵਾਪਸ ਕਰਦਾ ਹੈ ਜਿਸ ਨੂੰ React cleanup ਵੇਲੇ ਕਾਲ ਕਰੇਗਾ। |
| getSnapshot | External source ਤੋਂ ਮੌਜੂਦਾ value ਵਾਪਸ ਕਰਦਾ ਹੈ। ਇਹ referentially stable ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ—ਹਰ render 'ਤੇ ਇੱਕੋ function object—ਤਾਂ ਜੋ React snapshots ਦੀ ਸਹੀ ਤਰ੍ਹਾਂ ਤੁਲਨਾ ਕਰ ਸਕੇ। |
Browser ਦੇ online status ਲਈ ਇੱਕ minimal implementation ਇਸ ਤਰ੍ਹਾਂ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ:
function useOnlineStatus() {
return useSyncExternalStore(
(onChange) => {
window.addEventListener('online', onChange);
window.addEventListener('offline', onChange);
return () => {
window.removeEventListener('online', onChange);
window.removeEventListener('offline', onChange);
};
},
() => navigator.onLine
);
}
ਜਦੋਂ ਵੀ ਕੋਈ component useOnlineStatus() ਨੂੰ ਕਾਲ ਕਰਦਾ ਹੈ, ਤਾਂ React ਇਸਨੂੰ ਉਦੋਂ ਹੀ re-render ਕਰੇਗਾ ਜਦੋਂ navigator.onLine ਅਸਲ ਵਿੱਚ ਬਦਲੇਗਾ, ਅਤੇ ਹਰ render ਇੱਕੋ value ਦੇਖੇਗਾ।
ਨਿਯਮ ਜੋ hook ਨੂੰ ਖਰਾਬ ਹੋਣ ਤੋਂ ਬਚਾਉਂਦੇ ਹਨ
ਉਸ data ਦਾ ਸਭ ਤੋਂ ਛੋਟਾ ਹਿੱਸਾ ਵਾਪਸ ਕਰੋ ਜਿਸਦੀ component ਨੂੰ ਲੋੜ ਹੈ।
ਜੇਕਰ external store ਵਿੱਚ ਇੱਕ ਵੱਡਾ object ਹੈ ਪਰ component ਨੂੰ ਸਿਰਫ਼ ਇੱਕ field ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਸਿਰਫ਼ ਉਹੀ field ਵਾਪਸ ਕਰੋ। ਵੱਡੇ returns ਨਾਲ ਬੇਲੋੜੇ renders ਹੁੰਦੇ ਹਨ।getSnapshotਨੂੰ memoise ਕਰੋ।
ਜੇਕਰ ਤੁਸੀਂ ਹਰ render 'ਤੇ function ਨੂੰ ਦੁਬਾਰਾ ਬਣਾਉਂਦੇ ਹੋ, ਤਾਂ React ਇਸਨੂੰ ਇੱਕ ਨਵੇਂ source ਵਜੋਂ ਮੰਨਦਾ ਹੈ ਅਤੇ ਇਹ ਲਗਾਤਾਰ loop ਵਿੱਚ ਫਸ ਸਕਦਾ ਹੈ। ਇਸਨੂੰuseCallbackਵਿੱਚ ਲਪੇਟੋ (wrap) ਜਾਂ component ਦੇ ਬਾਹਰ define ਕਰੋ।ਹਰ ਕਾਲ 'ਤੇ ਨਵੇਂ objects ਵਾਪਸ ਕਰਨ ਤੋਂ ਬਚੋ।
ਇੱਕ ਨਵਾਂ object ਵਾਪਸ ਕਰਨਾ (ਜਿਵੇਂ ਕਿ{ count: store.getCount() }) ਹਰ render 'ਤੇ ਇੱਕ ਨਵਾਂ reference ਬਣਾਉਂਦਾ ਹੈ, ਜਿਸ ਨਾਲ React ਨੂੰ ਲੱਗਦਾ ਹੈ ਕਿ snapshot ਬਦਲ ਗਿਆ ਹੈ ਅਤੇ ਇਹ ਇੱਕ infinite render loop ਸ਼ੁਰੂ ਕਰ ਦਿੰਦਾ ਹੈ। Primitives, strings, numbers, ਜਾਂ memoised objects ਦੀ ਵਰਤੋਂ ਕਰੋ।ਇਸਦੀ ਵਰਤੋਂ internal component state ਲਈ ਨਾ ਕਰੋ।
ਉਹ data ਜੋ ਸਿਰਫ਼ component ਦੇ ਅੰਦਰ ਰਹਿੰਦਾ ਹੈ, ਉਸ ਲਈuseStateਅਜੇ ਵੀ ਸਹੀ tool ਹੈ।useSyncExternalStoreਵਾਧੂ overhead ਜੋੜਦਾ ਹੈ ਜਿਸਦੀ local state ਲਈ ਲੋੜ ਨਹੀਂ ਹੈ।
ਇਸਦੀ ਵਰਤੋਂ ਕਦੋਂ ਕਰਨੀ ਚਾਹੀਦੀ ਹੈ
- Browser APIs – window size, media queries,
navigator.onLine, battery status. - Framework-agnostic stores – Zustand, Redux, MobX, ਜਾਂ ਕੋਈ ਵੀ custom store ਜੋ subscription API ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।
- Mutable sources ਜੋ React ਤੋਂ ਬਾਹਰ update ਹੁੰਦੇ ਹਨ – WebSocket messages, IndexedDB change events, Service Worker notifications.
ਜੇਕਰ ਤੁਹਾਡਾ data source ਪਹਿਲਾਂ ਹੀ React ਦੇ ਅੰਦਰ ਹੈ (ਜਿਵੇਂ ਕਿ ਇੱਕ parent component ਦੀ state), ਤਾਂ useState ਜਾਂ context ਦੀ ਹੀ ਵਰਤੋਂ ਕਰੋ।
ਕਮਿਊਨਿਟੀ ਕੀ ਕਹਿ ਰਹੀ ਹੈ
ਸ਼ੁਰੂਆਤੀ ਵਰਤੋਂਕਾਰਾਂ (early adopters) ਦਾ ਕਹਿਣਾ ਹੈ ਕਿ useSyncExternalStore ਉਸ ਫਲਿੱਕਰ ਨੂੰ ਖਤਮ ਕਰ ਦਿੰਦਾ ਹੈ ਜੋ ਉਹਨਾਂ ਨੇ concurrent-rendering setup ਵਿੱਚ window resize ਕਰਦੇ ਸਮੇਂ ਦੇਖਿਆ ਸੀ। ਕੁਝ libraries ਪਹਿਲਾਂ ਹੀ ਆਪਣੇ internal hooks ਨੂੰ ਇਸ API ਵਿੱਚ ਬਦਲ ਚੁੱਕੀਆਂ ਹਨ, ਜੋ React ਦੇ ਵੱਖ-ਵੱਖ versions ਵਿੱਚ ਵਧੇਰੇ predictable ਵਿਵਹਾਰ ਦਾ ਵਾਅਦਾ ਕਰਦੀਆਂ ਹਨ। ਇਸਦਾ ਇੱਕ trade-off ਥੋੜ੍ਹਾ ਵਧੇਰੇ ਮਾਨਸਿਕ ਬੋਝ ਹੈ: developers ਨੂੰ ਦੋਵਾਂ functions ਦੀ stability ਬਾਰੇ ਸੋਚਣਾ ਪਵੇਗਾ ਅਤੇ ਹਰ ਕਾਲ 'ਤੇ ਨਵੇਂ objects ਵਾਪਸ ਕਰਨ ਤੋਂ ਬਚਣਾ ਪਵੇਗਾ।
ਅੱਗੇ ਕੀ ਦੇਖਣਾ ਹੈ
React ਦੀਆਂ ਆਉਣ ਵਾਲੀਆਂ ਰਿਲੀਜ਼ਾਂ useSyncExternalStore ਦੇ ਆਲੇ-ਦੁਆਲੇ ਦੇ ਨਿਯਮਾਂ ਨੂੰ ਹੋਰ ਸਖ਼ਤ ਕਰ ਸਕਦੀਆਂ ਹਨ, ਸ਼ਾਇਦ ਆਮ ਬ੍ਰਾਊਜ਼ਰ APIs ਲਈ ਬਿਲਟ-ਇਨ ਹੈਲਪਰਸ ਜੋੜ ਕੇ। ਪੁਰਾਣੇ useEffect-mirroring ਪੈਟਰਨ ਦੇ ਕਿਸੇ ਵੀ ਡਿਪ੍ਰੀਕੇਸ਼ਨ (deprecation) ਲਈ ਅਧਿਕਾਰਤ React ਬਲੌਗ 'ਤੇ ਨਜ਼ਰ ਰੱਖੋ। ਇਸ ਦੌਰਾਨ, ਇਹ ਹੁੱਕ ਸਥਿਰ (stable) ਹੈ ਅਤੇ ਪਬਲਿਕ API ਦਾ ਹਿੱਸਾ ਹੈ, ਇਸ ਲਈ ਤੁਸੀਂ ਮੌਜੂਦਾ external-state ਕੋਡ ਨੂੰ ਸੁਰੱਖਿਅਤ ਰੂਪ ਵਿੱਚ ਰੀਫੈਕਟਰ (refactor) ਕਰ ਸਕਦੇ ਹੋ।
ਤੇਜ਼ੀ ਨਾਲ ਟੈਸਟ ਕਰੋ
ਇੱਕ ਲਾਈਵ ਡੈਮੋ ਜੋ window-size syncing, online/offline detection, ਅਤੇ ਇੱਕ ਸਧਾਰਨ Zustand store ਨੂੰ ਦਰਸਾਉਂਦਾ ਹੈ, https://usesyncexternalstore.vercel.app/ 'ਤੇ ਉਪਲਬਧ ਹੈ। ਕਮੈਂਟਸ ਸਮੇਤ ਸੋਰਸ ਕੋਡ https://github.com/dev48v/usesyncexternalstore 'ਤੇ ਉਪਲਬਧ ਹੈ।
ਮੁੱਖ ਗੱਲ: useSyncExternalStore React ਨੂੰ ਕਿਸੇ ਵੀ ਅਜਿਹੇ mutable data ਲਈ ਇੱਕ ਭਰੋਸੇਯੋਗ ਬ੍ਰਿਜ (bridge) ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ ਜੋ ਇਸਦੇ render cycle ਤੋਂ ਬਾਹਰ ਹੁੰਦਾ ਹੈ, ਜੋ tearing ਅਤੇ ਬੇਲੋੜੇ renders ਨੂੰ ਰੋਕਦਾ ਹੈ। ਇਸਨੂੰ ਬਾਹਰੀ ਸਰੋਤਾਂ (external sources) 'ਤੇ ਲਾਗੂ ਕਰੋ, snapshot ਨੂੰ minimal ਅਤੇ stable ਰੱਖੋ, ਅਤੇ consistency ਬਣਾਈ ਰੱਖਣ ਦਾ ਮੁੱਖ ਕੰਮ React 'ਤੇ ਛੱਡ ਦਿਓ।
