React 18 मध्ये useSyncExternalStore जोडण्यात आले आहे, हा एक असा hook आहे जो components ला React tree च्या बाहेर असलेल्या कोणत्याही source कडून (उदा. browser APIs, WebSockets, किंवा third-party stores) डेटा वाचू देतो—आणि useState आणि useEffect वापरून तो डेटा mirror करण्याच्या जुन्या पद्धतीमुळे येणाऱ्या visual glitches पासून वाचवतो. जर तुम्ही कधी असा UI flicker पाहिला असेल जिथे विंडोचा काही भाग जुना आकार दाखवत होता आणि दुसरा भाग नवीन आकार दाखवत होता, तर हा hook तुमच्यासाठी तोच उपाय आहे ज्याची तुम्ही वाट पाहत होतात.

बाह्य state साठी नवीन hook ची गरज का आहे?

React components नेहमीच त्यांच्या स्वतःच्या scope च्या बाहेर असलेल्या गोष्टींना subscribe करण्यास सक्षम राहिले आहेत: जसे की window object, Redux store, किंवा WebSocket connection. पारंपारिक पद्धत म्हणजे useEffect मध्ये subscription सेट करणे, setState द्वारे येणाऱ्या values स्थानिक state मध्ये ढकलणे आणि React ला re-render होऊ देणे. जेव्हा React synchronously render करते तेव्हा हे व्यवस्थित काम करते, परंतु React 18 मध्ये concurrent rendering आणले गेले आहे, जिथे ब्राउझर प्रत्यक्षात paint करण्यापूर्वी component अनेक वेळा render होऊ शकतो. या mode मध्ये “mirror-into-local-state” पद्धतीमुळे 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 बदल whenever कॉल केला पाहिजे. हे एक unsubscribe function परत करते जे React cleanup वेळी कॉल करेल.
getSnapshot external source कडून सध्याची value परत करते. हे referentially stable असणे आवश्यक आहे—म्हणजेच प्रत्येक render वेळी तोच function object असावा—जेणेकरून React snapshots ची अचूक तुलना करू शकेल.

ब्राउझरच्या 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() कॉल करतो, तेव्हा navigator.onLine प्रत्यक्षात बदलला तरच React त्याला re-render करेल, आणि प्रत्येक render मध्ये तीच value दिसेल.

Hook मध्ये चुका टाळण्यासाठी काही नियम

  1. Component ला आवश्यक असलेला डेटाचा सर्वात लहान भाग परत करा.
    जर external store मध्ये एक मोठा object असेल पण component ला फक्त एकाच field ची गरज असेल, तर फक्त तेच field परत करा. मोठा डेटा परत केल्यामुळे अनावश्यक renders होतात.

  2. getSnapshot ला memoise करा.
    जर तुम्ही प्रत्येक render वेळी function पुन्हा तयार केले, तर React त्याला एक नवीन source समजते आणि यामुळे infinite loop तयार होऊ शकतो. त्याला useCallback मध्ये wrap करा किंवा component च्या बाहेर define करा.

  3. प्रत्येक कॉलला नवीन objects परत करणे टाळा.
    नवीन object परत केल्यामुळे (उदा. { count: store.getCount() }) प्रत्येक render वेळी एक नवीन reference तयार होतो, ज्यामुळे React ला वाटते की snapshot बदलला आहे आणि यामुळे infinite render loop सुरू होतो. Primitives, strings, numbers, किंवा memoised objects वापरा.

  4. याचा वापर internal component state साठी करू नका.
    जो डेटा केवळ component च्या आत असतो, त्यासाठी useState हेच योग्य साधन आहे. useSyncExternalStore मुळे असा overhead वाढतो ज्याची local state साठी गरज नाही.

याचा वापर कधी करावा?

  • Browser APIs – window size, media queries, navigator.onLine, battery status.
  • Framework-agnostic stores – Zustand, Redux, MobX, किंवा subscription API देणारे कोणतेही custom store.
  • React च्या बाहेर अपडेट होणारे mutable sources – WebSocket messages, IndexedDB change events, Service Worker notifications.

जर तुमचा data source आधीच React च्या आत असेल (उदा. parent component चा state), तर useState किंवा context चा वापर करा.

समुदाय काय म्हणत आहे

सुरुवातीच्या वापरकर्त्यांच्या मते, useSyncExternalStore मुळे concurrent-rendering सेटअपमध्ये विंडो resize करताना दिसणारा flicker निघून गेला आहे. काही libraries ने आधीच त्यांचे internal hooks या API कडे वळवले आहेत, ज्यामुळे React च्या विविध versions मध्ये अधिक predictable behavior मिळेल. याचा एकमेव drawback म्हणजे थोडा जास्त मानसिक ताण: developers ला त्या दोन functions च्या stability बद्दल विचार करावा लागेल आणि प्रत्येक कॉलला नवीन objects परत करणे टाळावे लागेल.

पुढे काय पाहावे

React च्या आगामी आवृत्त्या useSyncExternalStore च्या वापराबाबतचे नियम अधिक कडक करू शकतात, ज्यामध्ये कदाचित सामान्य ब्राउझर API साठी अंगभूत (built-in) हेल्पर्स जोडले जाऊ शकतात. जुन्या useEffect-mirroring पॅटर्नच्या कोणत्याही डेप्रिकेशनसाठी (deprecations) अधिकृत React ब्लॉगवर लक्ष ठेवा. तोपर्यंत, हा हुक स्थिर आहे आणि सार्वजनिक API चा भाग आहे, त्यामुळे तुम्ही सध्याचा एक्सटर्नल-स्टेट (external-state) कोड सुरक्षितपणे रिफॅक्टर (refactor) करू शकता.

जलद चाचणी

विंडो-साईज सिंक्रोनाइझेशन, ऑनलाइन/ऑफलाइन डिटेक्शन आणि एक साधे Zustand स्टोअर दर्शवणारा लाईव्ह डेमो https://usesyncexternalstore.vercel.app/ वर उपलब्ध आहे. कमेंट्ससह संपूर्ण सोर्स कोड https://github.com/dev48v/usesyncexternalstore वर उपलब्ध आहे.

थोडक्यात महत्त्वाचे: useSyncExternalStore React ला त्याच्या रेंडर सायकलच्या बाहेर असलेल्या कोणत्याही म्युटेबल (mutable) डेटासाठी एक विश्वसनीय पूल (bridge) प्रदान करते, ज्यामुळे 'tearing' आणि अनावश्यक रेंडर्स टाळता येतात. हे बाह्य स्रोतांना लागू करा, स्नॅपशॉट किमान आणि स्थिर ठेवा आणि सुसंगततेचे (consistency) कठीण काम React ला करू द्या.