زیادہ تر فرنٹ اینڈ کوڈ asynchronous کام کو ایک ہی شکل کے طور پر دیکھتا ہے۔ آپ ایک Promise شروع کرتے ہیں، اس کے حل ہونے کا انتظار کرتے ہیں، نتیجہ مقامی اسٹیٹ (local state) میں ڈال دیتے ہیں، اور فریم ورک کو فرق (diff) کو درست کرنے کے لیے چھوڑ دیتے ہیں۔ یہ پیٹرن پرکشش ہے کیونکہ یہ ہر جگہ کام کرتا ہے: ایک REST کال، فارم سبمیشن، یا WebSocket پیغام۔ یہ سب ایک ہی useEffect یا ایونٹ ہینڈلر میں آتے ہیں، سب setState کے ذریعے گزرتے ہیں، اور سب ایک جیسے async پلَمبنگ (plumbing) کی طرح نظر آتے ہیں۔ یہ یکسانیت ایک جال ہے۔ ایک حقیقی ایپلی کیشن میں، تمام async کام ایک جیسے نہیں ہوتے۔ ایسا ظاہر کرنا کہ وہ ایک جیسے ہیں، آپ کے UI کمپوننٹس کو حادثاتی طور پر ڈیٹا آرکیٹیکٹس بنا دیتا ہے، جو useEffect ہکس اور امیدوں کے سہارے جوڑے گئے ہوتے ہیں۔

درحقیقت async آپریشنز تین مختلف اقسام میں تقسیم ہوتے ہیں۔ ہر ایک کا وقت، کیشنگ (caching)، اور ملکیت (ownership) کے ساتھ مختلف تعلق ہوتا ہے۔ ان کے درمیان فرق کرنا سیکھنا ہی فرنٹ اینڈ کو تیز، درست اور مستحکم رکھتا ہے۔

Queries: Facts with an Address

ایک query محض ایک fetch نہیں ہے۔ یہ ایک قابلِ شناخت حقیقت کے لیے درخواست ہے۔ آپ /user/123 مانگ رہے ہیں، نہ کہ "کچھ صارف کا ڈیٹا"۔ یہ فرق اہم ہے کیونکہ شناخت ہی کیشنگ کو ممکن بناتی ہے۔ اگر ایک ہی اسکرین پر دو کمپوننٹس کو ایک ہی صارف کا ریکارڈ چاہیے، تو انہیں ایک ہی جواب شیئر کرنا چاہیے۔ جب ہر کمپوننٹ useState میں اپنی مقامی کاپی رکھتا ہے، تو آپ اپنی حقیقت کو ٹکڑوں میں تقسیم کر دیتے ہیں۔ ہیڈر میں موجود ایواٹار اور سائیڈ بار میں موجود نام ایک دوسرے سے الگ ہو جاتے ہیں کیونکہ وہ مختلف اوقات میں حاصل کیے گئے تھے، یا ایک ناکام ہو گیا جبکہ دوسرا کامیاب رہا۔

ایک query کو ایک ریسورس (resource) کے طور پر سوچیں، نہ کہ ایک ایکشن (action) کے طور پر۔ اس کی ایک cache key، ایک freshness policy، اور ایک لائف سائیکل ہوتا ہے جو کسی بھی انفرادی کمپوننٹ سے زیادہ طویل ہوتا ہے۔ ایک بہتر طور پر بنایا گیا query layer یہ سمجھتا ہے کہ /projects?page=2 پڑھنا /projects?page=3 پڑھنے سے مختلف ہے۔ ہر URL اور پیرامیٹر سیٹ ایک پتہ (address) بناتا ہے، اور اس پتے پر موجود ڈیٹا پرانا (stale)، تازہ (fresh)، یا غائب ہو سکتا ہے۔ UI کو یہ حساب کتاب نہیں رکھنا چاہیے۔ اسے ڈیٹا لیئر سے user:123 مانگنا چاہیے اور ایک snapshot حاصل کرنا چاہیے۔ آیا وہ snapshot دو سیکنڈ پہلے سرور سے آیا یا دو ملی سیکنڈ پہلے کیش سے، اس سے کمپوننٹ کا کوئی لینا دینا نہیں ہے۔

اس کا عملی نتیجہ فوری طور پر نظر آتا ہے۔ جب آپ ہر read کو کمپوننٹ کے اندر ایک imperative fetch کے طور پر دیکھتے ہیں، تو آپ deduplication کھو دیتے ہیں۔ آپ background refresh کھو دیتے ہیں۔ آپ پس منظر میں اسے درست (validate) کرتے ہوئے فوری طور پر کیش شدہ ڈیٹا دکھانے کی صلاحیت کھو دیتے ہیں۔ ایک query آپ کے UI ٹری سے باہر ایک گھر کی مستحق ہے۔

Mutations: Changing the World

اگر queries دنیا کے بارے میں پوچھتی ہیں، تو mutations اسے بدل دیتی ہیں۔ اصل نیٹ ورک ریکویسٹ—POST، PUT, یا DELETE—عام طور پر آسان حصہ ہوتی ہے۔ مشکل حصہ وہ سب کچھ ہے جو سرور کے "OK" کہنے کے بعد ہوتا ہے۔

فرض کریں کہ ایک صارف اپنا ڈسپلے نام اپ ڈیٹ کرتا ہے۔ خود mutation ایک واحد ریکویسٹ ہے۔ لیکن اس کا اثر (blast radius) ہر جگہ ہوتا ہے۔ پروفائل پیج پر پرانا نام ہے۔ نیویگیشن بار پر پرانا نام دکھ رہا ہے۔ کمنٹ ہسٹری اس کا حوالہ دے سکتی ہے۔ اگر آپ کا mutation کوڈ ایک مقامی isLoading فلیگ کو تبدیل کرنے اور پھر اسٹیٹ کے ایک حصے کو اپ ڈیٹ کرنے کے علاوہ کچھ نہیں کرتا، تو آپ کی ایپلی کیشن اب خود سے جھوٹ بول رہی ہے۔ UI کے کچھ حصے ظاہر کرتے ہیں کہ تبدیلی ہو گئی ہے۔ دوسروں کو اندازہ ہی نہیں ہوتا کہ کچھ بدلا بھی ہے۔

ایک mutation کو ڈیٹا گراف پر اپنے اثر کا اعلان کرنا چاہیے۔ اسے سسٹم کو بتانا چاہیے کہ اب کون سی queries غیر معتبر (invalid) ہیں، کن کیش شدہ keys کو دوبارہ حاصل (refetch) کرنے کی ضرورت ہے، اور کون سے تعلقات بدل گئے ہیں۔ یہ بنیادی طور پر ایک query سے مختلف ہے۔ ایک query صرف پڑھنے کے لیے (read-only) اور شیئر کرنے کے قابل ہوتی ہے۔ ایک mutation لکھنے پر مرکوز (write-focused) ہوتی ہے اور موجودہ کیشز کو ختم کر دیتی ہے۔ انہیں ایک ہی ابسٹریشن (abstraction) میں سمونے کا مطلب یہ ہے کہ ڈویلپرز آخر کار مختلف کمپوننٹس کے اندر دستی طور پر refetch() کال کرنے لگتے ہیں، یا اس سے بھی بدتر، مقامی اسٹیٹ کو سرور کے ساتھ ہم آہنگ کرنے کے لیے پورے ٹری میں useEffect ہکس بکھیر دیتے ہیں۔

ملکیت کا ماڈل بھی مختلف ہے۔ Queries عام طور پر کیش (cache) کی ملکیت ہوتی ہیں۔ ایک mutation اس صارف کے ایکشن کی ملکیت ہوتی ہے جس نے اسے ٹرگر کیا۔ اس کی ایک pending state، ایک error state، اور ممکنہ طور پر ایک optimistic value ہوتی ہے جسے رولڈ