useSyncExternalStore అనేది కన్కరెంట్ రెండరింగ్ (concurrent rendering) వల్ల కలిగే విజువల్ గ్లిచెస్ (visual glitches) లేకుండా, React వెలుపల ఉండే డేటాను ఒక కాంపోనెంట్ చదవడానికి అనుమతిస్తుంది. ఇది useEffect ఉపయోగించి ఎక్స్‌టర్నల్ వాల్యూస్‌ను లోకల్ స్టేట్‌లోకి తీసుకువచ్చే పాత పద్ధతిని భర్తీ చేస్తుంది. ఆ పాత పద్ధతి వల్ల "tearing" జరగవచ్చు – అంటే ఒకే రెండర్ సమయంలో UIలోని కొన్ని భాగాలు వేర్వేరు విలువలను చూపించడం.

కన్కరెన్సీ (concurrency) కింద పాత పద్ధతి ఎందుకు విఫలమవుతుంది

React 18 కంటే ముందు, సాధారణ పద్ధతి ఇది:

const [value, setValue] = useState(initial);
useEffect(() => {
  const unsubscribe = externalSource.subscribe(v => setValue(v));
  return unsubscribe;
}, []);

కాంపోనెంట్ రెండర్ అయిన తర్వాత ఈ ఎఫెక్ట్ (effect) రన్ అవుతుంది. React యొక్క కన్కరెంట్ రెండరర్ ఒక రెండర్‌ను ఆపాలని, రద్దు చేయాలని లేదా మళ్ళీ ప్లే చేయాలని నిర్ణయించినప్పుడు, స్టేట్‌ను చదివే UI కంటే భిన్నమైన సమయంలో ఈ ఎఫెక్ట్ రన్ అయ్యే అవకాశం ఉంది. దీని ఫలితంగా ఒక అసమతుల్యత (mismatch) ఏర్పడుతుంది: ఒక కాంపోనెంట్ పాత విలువను చదివితే, మరొకటి కొత్త విలువను చదవవచ్చు, దీనివల్ల స్క్రీన్ స్వల్పకాలికంగా అస్థిరమైన డేటాను చూపుతుంది. పూర్తిగా సింక్రోనస్ (synchronous) ప్రపంచంలో ఈ "tearing" హానికరమైనది కాదు, కానీ React ఒకేసారి UI యొక్క బహుళ వెర్షన్లను ప్యారలల్‌గా రెండర్ చేస్తున్నప్పుడు ఇది ఒక స్పష్టమైన బగ్‌గా మారుతుంది.

useSyncExternalStore సమస్యను ఎలా పరిష్కరిస్తుంది

ఈ హుక్ (hook) రెండు కాల్‌బ్యాక్‌లను (callbacks) కోరుతుంది:

  • subscribe – ఇది ఒక లిజనర్‌ను రిజిస్టర్ చేస్తుంది మరియు దానిని తొలగించడానికి ఒక ఫంక్షన్‌ను తిరిగి ఇస్తుంది.
  • getSnapshot – ఇది ఎక్స్‌టర్నల్ సోర్స్ యొక్క ప్రస్తుత విలువను తిరిగి ఇస్తుంది.

కాంపోనెంట్ మౌంట్ (mount) అయినప్పుడు React subscribeని పిలుస్తుంది మరియు అన్‌మౌంట్ (unmount) అయినప్పుడు దానిని తొలగిస్తుంది. ప్రతి రెండర్ సమయంలో ఇది getSnapshotని పిలుస్తుంది మరియు ఒకే ఎక్స్‌టర్నల్ స్టోర్‌ను ఉపయోగించే అన్ని కాంపోనెంట్లు ఖచ్చితంగా ఒకే స్నాప్‌షాట్‌ను చదువుతాయని హామీ ఇస్తుంది. ఈ రీడ్ (read) ప్రక్రియ రెండర్ దశలోనే జరుగుతుంది కాబట్టి, రెండరర్ మొత్తం ట్రీ అంతటా అప్‌డేట్‌లను సమన్వయం చేయగలదు, తద్వారా tearing ని నివారిస్తుంది.

Zustand మరియు Redux వంటి లైబ్రరీలు ఇప్పటికే తమ స్టోర్‌లను ఈ హుక్‌తో కలిపి వాడుతున్నాయి, అందుకే అవి React 18 యొక్క కన్కరెంట్ ఫీచర్లతో నేరుగా పనిచేస్తాయి.

హుక్ తప్పుగా ప్రవర్తించకుండా ఉండే నియమాలు

  1. కాంపోనెంట్‌కు అవసరమైన దానిని మాత్రమే రిటర్న్ చేయండి – పెద్ద ఆబ్జెక్ట్‌ను రిటర్న్ చేయడం వల్ల ప్రతి అప్‌డేట్‌లో React లోతైన స్ట్రక్చర్లను (deep structures) పోల్చాల్సి వస్తుంది. చిన్న స్నాప్‌షాట్ వాడటం వల్ల మార్పులను గుర్తించడం సులభం అవుతుంది.
  2. రిఫరెన్షియల్ ఐడెంటిటీని (referential identity) కాపాడండి – ఎక్స్‌టర్నల్ వాల్యూ మారనట్లయితే, getSnapshot అదే ఆబ్జెక్ట్ రిఫరెన్స్‌ను తిరిగి ఇవ్వాలి. ప్రతిసారీ కొత్త ఆబ్జెక్ట్‌ను రిటర్న్ చేయడం వల్ల ఇన్ఫినిట్ రెండర్ లూప్ (infinite render loop) ఏర్పడుతుంది, ఎందుకంటే ప్రతి రెండర్‌లోనూ మార్పు జరిగినట్లు React భావిస్తుంది.
  3. ఎక్స్‌టర్నల్ సోర్స్‌లకు మాత్రమే పరిమితం చేయండి – లోకల్ కాంపోనెంట్ స్టేట్ అనేది useState లేదా useReducerలో ఉండాలి. కేవలం ఇంటర్నల్ వాల్యూస్ కోసం ఎక్స్‌టర్నల్-స్టోర్ హుక్‌ను ఉపయోగించడం అనవసరమైన సంక్లిష్టతను పెంచుతుంది.

useSyncExternalStore ఎప్పుడు ఉపయోగించాలి

  • బ్రౌజర్ APIలను (window size, network-online status, media queries) చుట్టూ ప్యాక్ చేయడానికి (wrapping).
  • React గురించి తెలియని ఒక ప్లెయిన్ JavaScript స్టోర్‌ను కనెక్ట్ చేయడానికి.
  • ప్రాప్-డ్రిల్లింగ్ (prop-drilling) స్థానంలో, చాలా కాంపోనెంట్లు సబ్‌స్క్రైబ్ అయ్యే గ్లోబల్ రీడ్-ఓన్లీ సోర్స్‌ను ఉపయోగించడానికి.

వ్యతిరేక వాదన (The counter-argument)

తక్కువగా మారే సాధారణ డేటా కోసం, ముఖ్యంగా అప్లికేషన్ కన్కరెంట్ ఫీచర్లను ఎనేబుల్ చేయనప్పుడు, useState + useEffect పద్ధతి ఇప్పటికీ పనిచేస్తుంది. ఇది తక్కువ స్థాయి (lower-level) విధానం, దీనివల్ల సబ్‌స్క్రిప్షన్ లాజిక్ స్పష్టంగా ఎఫెక్ట్‌లో ఉంటుంది కాబట్టి కొంతమంది డెవలపర్‌లకు ఇది సులభంగా అనిపించవచ్చు. అయితే, కన్కరెంట్ రెండరింగ్ ఆన్ చేసినప్పుడు tearing రిస్క్ ఉంటుంది. ఇప్పటికే React 18 యొక్క కొత్త సామర్థ్యాలను ఉపయోగిస్తున్న ప్రాజెక్ట్‌ల కోసం, useSyncExternalStore ఇచ్చే అదనపు భద్రత, దానితో వచ్చే స్వల్ప అదనపు కోడ్ (boilerplate) కంటే చాలా ఉత్తమం.

తదుపరి ఏం గమనించాలి

  • మీ స్టోర్ యొక్క getSnapshot స్థిరమైన రిఫరెన్స్‌ను (stable reference) తిరిగి ఇస్తుందని నిర్ధారించుకోండి; డెవలప్‌మెంట్ సమయంలో రిఫరెన్స్‌ను console.log చేయడం ద్వారా అనుకోకుండా ఆబ్జెక్ట్‌లు మళ్ళీ క్రియేట్ అవుతున్నాయో లేదో తెలుసుకోవచ్చు.
  • సబ్‌స్క్రిప్షన్ ఫంక్షన్‌ను లైట్‌వెయిట్‌గా (lightweight) ఉంచండి – భారీ పనులు ఎక్స్‌టర్నల్ సోర్స్ లోపల జరగాలి, React కి పంపే కాల్‌బ్యాక్‌లో కాదు.
  • ఎటువంటి tearing కనిపించదని నిర్ధారించుకోవడానికి React కన్కరెంట్ మోడ్‌లో (ఉదాహరణకు, ReactDOM.createRootతో act ఉపయోగించి) కాంపోనెంట్లను టెస్ట్ చేయండి.

ఒక లైవ్ డెమో ఈ హుక్ ఎలా పనిచేస్తుందో చూపిస్తుంది, ఇది React వెలుపల నిల్వ చేయబడిన ఒక సింపుల్ కౌంటర్‌ను సింక్ చేస్తూ, విజువల్ గ్లిచెస్ లేకుండా బహుళ కాంపోనెంట్లను అప్‌డేట్ చేస్తుంది. డెమో https://usesyncexternalstore.vercel.app/ లో అందుబాటులో ఉంది. దీని సోర్స్ కోడ్ GitHubలో ఉంది, మరియు ఒక సుదీర్ఘమైన వివరణ దాని ఇంప్లిమెంటేషన్ వివరాలను వివరిస్తుంది.

Takeaway: UI యొక్క కొన్ని భాగాలను క్రమ పద్ధతిలో కాకుండా (out of order) రెండర్ చేయగల React ప్రపంచంలో, useSyncExternalStore అనేది ఎక్స్‌టర్నల్ డేటా మరియు కాంపోనెంట్ రెండరింగ్ మధ్య నమ్మకమైన వంతెన. ఇది విజువల్ కన్సిస్టెన్సీని కాపాడుతుంది, గ్లోబల్ స్టోర్‌లకు స్కేల్ అవుతుంది మరియు ఇప్పటికే పాపులర్ స్టేట్-మేనేజ్‌మెంట్ లైబ్రరీలలో భాగంగా ఉంది. మీరు నాన్-React స్టేట్‌ను చదవాల్సిన చోట దీనిని ఉపయోగించండి, మరియు దాని పూర్తి ప్రయోజనాలను పొందడానికి స్నాప్‌షాట్‌లను చిన్నవిగా మరియు స్థిరంగా ఉంచండి.