React 18, useSyncExternalStore అనే కొత్త హుక్‌ను జోడించింది. ఇది React ట్రీ వెలుపల ఉండే ఏ మూలం నుండి అయినా—అంటే browser APIs, WebSockets, లేదా third-party stores—డేటాను రీడ్ చేయడానికి కాంపోనెంట్లను అనుమతిస్తుంది. పాత పద్ధతిలో useState మరియు useEffect ఉపయోగించి డేటాను మిర్రరింగ్ (mirroring) చేసినప్పుడు వచ్చే విజువల్ గ్లిచెస్ (visual glitches) లేకుండా ఇది పనిచేస్తుంది. ఒక విండో సైజు మారినప్పుడు UIలో ఒక భాగం పాత సైజును, మరొక భాగం కొత్త సైజును చూపిస్తూ ఫ్లిక్కర్ (flicker) అవ్వడం మీరు ఎప్పుడైనా గమనించినట్లయితే, ఈ హుక్ మీరు ఎదురుచూస్తున్న పరిష్కారం.

ఎందుకు ఎక్స్‌టర్నల్ స్టేట్‌కి కొత్త హుక్ అవసరం?

React కాంపోనెంట్‌లు ఎప్పుడూ వాటి పరిధి వెలుపల ఉన్న వాటిని సబ్‌స్క్రైబ్ (subscribe) చేయగలవు: ఉదాహరణకు window ఆబ్జెక్ట్, Redux స్టోర్, లేదా WebSocket కనెక్షన్. సాంప్రదాయ పద్ధతి ప్రకారం, useEffect లోపల సబ్‌స్క్రిప్షన్‌ను సెటప్ చేసి, వచ్చే విలువలను setState ద్వారా లోకల్ స్టేట్‌లోకి పంపి, React ని రీ-రెండర్ చేయించేవారు. React సింక్రోనస్‌గా (synchronously) రెండర్ అయినప్పుడు ఇది బాగానే పనిచేస్తుంది, కానీ React 18 లో కన్కరెంట్ రెండరింగ్ (concurrent rendering) ప్రవేశపెట్టబడింది. ఇందులో బ్రౌజర్ నిజంగా పెయింట్ (paint) చేయకముందే ఒక కాంపోనెంట్ బహుళ సార్లు రెండర్ అయ్యే అవకాశం ఉంది. ఈ మోడ్‌లో "mirror-into-local-state" పద్ధతి tearing కు దారితీయవచ్చు—అంటే ఒకే రెండర్ సైకిల్‌లో UI యొక్క వేర్వేరు భాగాలు ఒకే ఎక్స్‌టర్నల్ వాల్యూ యొక్క వేర్వేరు స్నాప్‌షాట్‌లను (snapshots) చదివే ప్రమాదం ఉంది.

Tearing ని నివారించడానికి useSyncExternalStore రూపొందించబడింది. ఇది ఎక్స్‌టర్నల్ సోర్స్ నుండి ఒక snapshot (ప్రస్తుత విలువ) మరియు ఒక subscribe ఫంక్షన్ (మార్పులు జరిగినప్పుడు ఎలా తెలియజేయాలి అనేది) అడుగుతుంది. కాంపోనెంట్ మౌంట్ (mount) అయినప్పుడు React subscribeని కాల్ చేస్తుంది మరియు అన్‌మౌంట్ (unmount) అయినప్పుడు ఆటోమేటిక్‌గా అన్‌సబ్‌స్క్రైబ్ చేస్తుంది. getSnapshot ద్వారా రిటర్న్ చేయబడిన స్నాప్‌షాట్ మారినప్పుడల్లా, React మొత్తం కాంపోనెంట్ ట్రీ కోసం ఒకే స్నాప్‌షాట్‌ను చదివేలా ఒక రెండర్‌ను షెడ్యూల్ చేస్తుంది, తద్వారా స్థిరత్వాన్ని (consistency) నిర్ధారిస్తుంది.

అవసరమైన రెండు ఫంక్షన్లు

ఫంక్షన్ ఇది ఏమి చేస్తుంది
subscribe ఎక్స్‌టర్నల్ వాల్యూ మారినప్పుడల్లా కాల్ చేయాల్సిన కాల్‌బ్యాక్‌ను ఇది స్వీకరిస్తుంది. ఇది ఒక unsubscribe ఫంక్షన్‌ను రిటర్న్ చేస్తుంది, దీనిని React క్లీనప్ సమయంలో కాల్ చేస్తుంది.
getSnapshot ఎక్స్‌టర్నల్ సోర్స్ నుండి ప్రస్తుత విలువను రిటర్న్ చేస్తుంది. ఇది referentially stable గా ఉండాలి—అంటే ప్రతి రెండర్‌లోనూ ఒకే ఫంక్షన్ ఆబ్జెక్ట్ ఉండాలి—అప్పుడే React స్నాప్‌షాట్‌లను సరిగ్గా పోల్చగలదు.

బ్రౌజర్ యొక్క online స్టేటస్ కోసం ఒక చిన్న ఇంప్లిమెంటేషన్ ఇలా ఉంటుంది:

function useOnlineStatus() {
  return useSyncExternalStore(
    (onChange) => {
      window.addEventListener('online', onChange);
      window.addEventListener('offline', onChange);
      return () => {
        window.removeEventListener('online', onChange);
        window.removeEventListener('offline', onChange);
      };
    },
    () => navigator.onLine
  );
}

ఏదైనా కాంపోనెంట్ useOnlineStatus()ని కాల్ చేసినప్పుడు, navigator.onLine నిజంగా మారినప్పుడు మాత్రమే React దానిని రీ-రెండర్ చేస్తుంది, మరియు ప్రతి రెండర్ ఒకే విలువను చూస్తుంది.

హుక్ సరిగ్గా పనిచేయడానికి పాటించాల్సిన నియమాలు

  1. కాంపోనెంట్‌కు అవసరమైన అతి తక్కువ డేటాను మాత్రమే రిటర్న్ చేయండి.
    ఎక్స్‌టర్నల్ స్టోర్‌లో పెద్ద ఆబ్జెక్ట్ ఉన్నప్పటికీ, ఒక కాంపోనెంట్‌కు కేవలం ఒక ఫీల్డ్ మాత్రమే కావాలంటే, ఆ ఫీల్డ్‌ను మాత్రమే రిటర్న్ చేయండి. పెద్ద డేటాను రిటర్న్ చేయడం వల్ల అనవసరమైన రీ-రెండర్లు జరుగుతాయి.

  2. getSnapshotను మెమోయిజ్ (Memoise) చేయండి.
    మీరు ప్రతి రెండర్‌లోనూ ఫంక్షన్‌ను మళ్ళీ సృష్టిస్తే, React దానిని కొత్త సోర్స్ అని భావించి అనంతమైన లూప్‌లోకి (infinite loop) వెళ్ళవచ్చు. దీనిని useCallbackలో చుట్టండి లేదా కాంపోనెంట్ వెలుపల నిర్వచించండి.

  3. ప్రతి కాల్‌లో కొత్త ఆబ్జెక్ట్‌లను రిటర్న్ చేయవద్దు.
    కొత్త ఆబ్జెక్ట్‌ను రిటర్న్ చేయడం (ఉదాహరణకు, { count: store.getCount() }) ప్రతి రెండర్‌లోనూ కొత్త రిఫరెన్స్‌ను సృష్టిస్తుంది, దీనివల్ల స్నాప్‌షాట్ మారిందని React భావించి అనంతమైన రెండర్ లూప్‌ను ప్రారంభిస్తుంది. ప్రిమిటివ్స్ (primitives), స్ట్రింగ్స్, నంబర్స్ లేదా మెమోయిజ్డ్ ఆబ్జెక్ట్‌లను ఉపయోగించండి.

  4. దీనిని ఇంటర్నల్ కాంపోనెంట్ స్టేట్ కోసం ఉపయోగించవద్దు.
    కేవలం కాంపోనెంట్ లోపల మాత్రమే ఉండే డేటా కోసం useState సరైన సాధనం. లోకల్ స్టేట్ కోసం useSyncExternalStore అవసరం లేని ఓవర్‌హెడ్‌ను జోడిస్తుంది.

దీనిని ఎప్పుడు ఉపయోగించాలి

  • Browser APIs – window size, media queries, navigator.onLine, battery status.
  • Framework-agnostic stores – Zustand, Redux, MobX, లేదా సబ్‌స్క్రిప్షన్ APIని ఎక్స్‌పోజ్ చేసే ఏదైనా కస్టమ్ స్టోర్.
  • React వెలుపల అప్‌డేట్ అయ్యే మ్యూటబుల్ సోర్సెస్ (Mutable sources) – WebSocket మెసేజ్‌లు, IndexedDB మార్పు ఈవెంట్‌లు, Service Worker నోటిఫికేషన్‌లు.

మీ డేటా సోర్స్ ఇప్పటికే React లోపల ఉంటే (ఉదాహరణకు, ఒక పేరెంట్ కాంపోనెంట్ స్టేట్), useState లేదా context ను మాత్రమే ఉపయోగించండి.

కమ్యూనిటీ ఏమంటోంది

కన్కరెంట్-రెండరింగ్ సెటప్‌లో విండోలను రీసైజ్ చేస్తున్నప్పుడు కనిపించే ఫ్లిక్కర్‌ను useSyncExternalStore తొలగిస్తుందని ప్రారంభ వినియోగదారులు చెబుతున్నారు. కొన్ని లైబ్రరీలు ఇప్పటికే తమ ఇంటర్నల్ హుక్‌లను ఈ APIకి మార్చాయి, ఇది వివిధ React వెర్షన్లలో మరింత ఊహించదగిన (predictable) ప్రవర్తనను అందిస్తుంది. అయితే, దీని వల్ల డెవలపర్‌లపై కొంచెం మానసిక భారం పెరుగుతుంది: డెవలపర్లు ఆ రెండు ఫంక్షన్‌ల స్థిరత్వం (stability) గురించి ఆలోచించాలి మరియు ప్రతి కాల్‌లో కొత్త ఆబ్జెక్ట్‌లను రిటర్న్ చేయకుండా జాగ్రత్త పడాలి.

తదుపరి ఏమి చూడాలి

React యొక్క రాబోయే విడుదలలు useSyncExternalStore చుట్టూ ఉన్న నిబంధనలను మరింత కఠినతరం చేయవచ్చు, బహుశా సాధారణ బ్రౌజర్ APIల కోసం built-in హెల్పర్లను కూడా జోడించవచ్చు. పాత useEffect-mirroring పద్ధతికి సంబంధించి ఏవైనా deprecations వస్తే తెలుసుకోవడానికి అధికారిక React బ్లాగ్‌ను గమనిస్తూ ఉండండి. ప్రస్తుతానికి, ఈ hook స్థిరంగా ఉంది మరియు public APIలో భాగంగా ఉంది, కాబట్టి మీరు ఇప్పటికే ఉన్న external-state కోడ్‌ను సురక్షితంగా refactor చేయవచ్చు.

త్వరిత పరీక్ష

window-size syncing, online/offline detection, మరియు ఒక సాధారణ Zustand storeను ప్రదర్శించే లైవ్ డెమో https://usesyncexternalstore.vercel.app/ లో అందుబాటులో ఉంది. కామెంట్లతో కూడిన source code, https://github.com/dev48v/usesyncexternalstore లో అందుబాటులో ఉంది.

ముఖ్య అంశం: useSyncExternalStore అనేది దాని render cycle వెలుపల ఉండే ఏవైనా mutable dataకు React కి ఒక నమ్మకమైన వంతెనలా పనిచేస్తుంది, దీనివల్ల tearing మరియు అనవసరమైన renders నివారించబడతాయి. దీనిని external sourcesకు వర్తింపజేయండి, snapshotను కనిష్టంగా మరియు స్థిరంగా ఉంచండి, మరియు consistency కోసం కష్టమైన పనులను React కే వదిలేయండి.