useSyncExternalStore ایک کمپوننٹ کو ایسا ڈیٹا پڑھنے کی اجازت دیتا ہے جو React سے باہر موجود ہو، بغیر ان بصری خرابیوں (visual glitches) کے خطرے کے جو کنکرنٹ رینڈرنگ (concurrent rendering) پیدا کر سکتی ہیں۔ یہ بیرونی ویلیوز کو useEffect کے ذریعے لوکل اسٹیٹ میں لانے کے پرانے پیٹرن کا متبادل ہے، جو کہ ایک ایسا پیٹرن ہے جس کی وجہ سے "tearing" ہو سکتی ہے – یعنی UI کے مختلف حصے ایک ہی رینڈر کے دوران مختلف ویلیوز دکھا سکتے ہیں۔

کنکرنسی (concurrency) کے دوران پرانا پیٹرن کیوں ناکام ہو جاتا ہے

React 18 سے پہلے، عام طریقہ کار یہ تھا:

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

ایفیکٹ (effect) تب چلتا ہے جب کمپوننٹ رینڈر ہو چکا ہو۔ جب React کا کنکرنٹ رینڈرر کسی رینڈر کو روکنے، منسوخ کرنے، یا دوبارہ چلانے کا فیصلہ کرتا ہے، تو ایفیکٹ اس وقت سے مختلف مقام پر چل سکتا ہے جب UI اسٹیٹ کو پڑھ رہا ہو۔ اس کا نتیجہ عدم مطابقت کی صورت میں نکلتا ہے: ایک کمپوننٹ نے پرانی ویلیو پڑھی ہو گی، جبکہ دوسرے نے نئی، اور اسکرین عارضی طور پر غیر مستقل ڈیٹا دکھاتی ہے۔ یہ "tearing" خالصتاً سنکرونس (synchronous) دنیا میں بے ضرر ہے لیکن جب React متوازی طور پر UI کے متعدد ورژن رینڈر کرتا ہے تو یہ ایک واضح بگ (bug) بن جاتا ہے۔

useSyncExternalStore اس مسئلے کو کیسے حل کرتا ہے

اس ہک (hook) کے لیے دو کال بیکس (callbacks) درکار ہوتے ہیں:

  • subscribe – ایک لسنر (listener) رجسٹر کرتا ہے اور ایک ایسا فنکشن واپس کرتا ہے جو اسے ہٹا دیتا ہے۔
  • getSnapshot – بیرونی ذریعے (external source) کی موجودہ ویلیو واپس کرتا ہے۔

React subscribe کو تب کال کرتا ہے جب کمپوننٹ ماؤنٹ (mount) ہوتا ہے اور ان ماؤنٹ (unmount) پر اسے ختم کر دیتا ہے۔ ہر رینڈر کے دوران یہ getSnapshot کو کال کرتا ہے اور اس بات کی ضمانت دیتا ہے کہ ایک ہی بیرونی اسٹور استعمال کرنے والے تمام کمپوننٹس بالکل ایک ہی اسنیپ شاٹ (snapshot) پڑھیں۔ چونکہ یہ ریڈ (read) رینڈر فیز کے اندر ہوتا ہے، اس لیے رینڈرر پورے ٹری (tree) میں اپ ڈیٹس کو ہم آہنگ کر سکتا ہے، جس سے ٹیئرنگ (tearing) ختم ہو جاتی ہے۔

Zustand اور Redux جیسی لائبریریاں پہلے سے ہی اپنے اسٹورز کو اس ہک کے ساتھ لپیٹ (wrap) دیتی ہیں، یہی وجہ ہے کہ وہ React 18 کے کنکرنٹ فیچرز کے ساتھ براہ راست کام کرتی ہیں۔

وہ اصول جو ہک کو غلط کام کرنے سے روکتے ہیں

  1. صرف وہی واپس کریں جس کی کمپوننٹ کو ضرورت ہو – ایک بڑا آبجیکٹ React کو ہر اپ ڈیٹ پر گہری ساختوں (deep structures) کا موازنہ کرنے پر مجبور کرتا ہے۔ ایک محدود اسنیپ شاٹ تبدیلیوں کی نشاندہی (change detection) کو سستا رکھتا ہے۔
  2. ریفرینشل آئیڈینٹیٹی (referential identity) برقرار رکھیں – اگر بیرونی ویلیو تبدیل نہیں ہوئی ہے، تو getSnapshot کو وہی آبجیکٹ ریفرنس واپس کرنا چاہیے۔ ہر کال پر نیا آبجیکٹ واپس کرنے سے انفینٹ رینڈر لوپ (infinite render loop) شروع ہو جاتا ہے کیونکہ React ہر رینڈر پر تبدیلی دیکھتا ہے۔
  3. استعمال کو صرف بیرونی ذرائع تک محدود رکھیں – لوکل کمپوننٹ اسٹیٹ useState یا useReducer میں ہونی چاہیے۔ خالصتاً اندرونی ویلیوز کے لیے بیرونی اسٹور ہک کا استعمال غیر ضروری پیچیدگی پیدا کرتا ہے۔

useSyncExternalStore کا استعمال کب کریں

  • براؤزر APIs (window size, network-online status, media queries) کو ریپ (wrap) کرنے کے لیے۔
  • ایک سادہ JavaScript اسٹور کو جوڑنے کے لیے جسے React کے بارے میں علم نہ ہو۔
  • Prop-drilling کو ایک عالمی ریڈ-اونلی (global read-only) ذریعے سے بدلنے کے لیے جس میں بہت سے کمپوننٹس سبسکرائب ہوں۔

مخالف دلیل (The counter-argument)

useState + useEffect کا پیٹرن اب بھی سادہ اور کم تبدیل ہونے والے ڈیٹا کے لیے کام کرتا ہے، خاص طور پر جب کوئی ایپلی کیشن کنکرنٹ فیچرز کو فعال نہ کرے۔ یہ ایک لو-لیول (lower-level) طریقہ کار ہے جسے کچھ ڈویلپرز کے لیے سمجھنا آسان ہوتا ہے کیونکہ سبسکرپشن لاجک واضح طور پر ایفیکٹ میں موجود ہوتی ہے۔ تاہم، اس کا نقصان یہ ہے کہ کنکرنٹ رینڈرنگ آن ہونے پر ٹیئرنگ (tearing) کا خطرہ رہتا ہے۔ ان پروجیکٹس کے لیے جو پہلے سے ہی React 18 کی نئی صلاحیتوں کا استعمال کر رہے ہیں، useSyncExternalStore کی اضافی حفاظت کم سے کم بوائلر پلیٹ (boilerplate) کے مقابلے میں زیادہ اہمیت رکھتی ہے۔

آگے کیا دیکھیں

  • تصدیق کریں کہ آپ کے اسٹور کا getSnapshot ایک مستحکم ریفرنس واپس کرتا ہے؛ ڈویلپمنٹ کے دوران ریفرنس کا ایک فوری console.log حادثاتی طور پر آبجیکٹ کی دوبارہ تخلیق کو ظاہر کر سکتا ہے۔
  • سبسکرپشن فنکشن کو ہلکا پھلکا رکھیں – بھاری کام بیرونی ذریعے کے اندر ہونا چاہیے، نہ کہ React کو پاس کیے گئے کال بیک میں۔
  • React کے کنکرنٹ موڈ کے تحت کمپوننٹس کا ٹیسٹ کریں (مثلاً act کو ReactDOM.createRoot کے ساتھ استعمال کرتے ہوئے) تاکہ اس بات کی تصدیق ہو سکے کہ کوئی ٹیئرنگ ظاہر نہیں ہو رہی۔

ایک لائیو ڈیمو ہک کو عملی طور پر دکھاتا ہے، جو React سے باہر محفوظ ایک سادہ کاؤنٹر کو سنک (sync) کرتا ہے اور بصری خرابیوں کے بغیر متعدد کمپوننٹس کو اپ ڈیٹ کرتا ہے۔ ڈیمو اس لنک پر دستیاب ہے: https://usesyncexternalstore.vercel.app/۔ اس کا سورس کوڈ GitHub پر موجود ہے، اور ایک تفصیلی تحریر اس کی امپلیمنٹیشن کی تفصیلات بتاتی ہے۔

خلاصہ (Takeaway): ایک ایسی دنیا میں جہاں React UI کے حصوں کو ترتیب سے باہر رینڈر کر سکتا ہے، useSyncExternalStore بیرونی ڈیٹا اور کمپوننٹ رینڈرنگ کے درمیان ایک قابل اعتماد پل ہے۔ یہ بصری تسلسل برقرار رکھتا ہے، گلوبل اسٹورز تک پھیل سکتا ہے، اور پہلے سے ہی مقبول اسٹیٹ مینجمنٹ لائبریریوں میں شامل ہے۔ جہاں بھی آپ کو نان-React (non-React) اسٹیٹ پڑھنے کی ضرورت ہو، اسے اپنائیں، اور مکمل فوائد حاصل کرنے کے لیے اسنیپ شاٹس کو چھوٹا اور مستحکم رکھیں۔