മിക്ക ഫ്രണ്ട്എൻഡ് കോഡുകളും അസിൻക്രണസ് (asynchronous) പ്രവർത്തനങ്ങളെ ഒരേ രീതിയിലുള്ള ഒന്നായിട്ടാണ് കാണുന്നത്. നിങ്ങൾ ഒരു Promise തുടങ്ങുന്നു, അത് റെസൾവ് (resolve) ആകുന്നത് വരെ കാത്തിരിക്കുന്നു, ഫലം ലോക്കൽ സ്റ്റേറ്റിലേക്ക് (local state) മാറ്റുന്നു, തുടർന്ന് ഫ്രെയിംവർക്ക് വ്യത്യാസങ്ങൾ ക്രമീകരിക്കുന്നു. ഈ രീതി എല്ലാടത്തും പ്രവർത്തിക്കുന്നതുകൊണ്ട് ഇത് ആകർഷകമാണ്: ഒരു REST കോൾ, ഒരു ഫോം സബ്മിഷൻ, അല്ലെങ്കിൽ ഒരു WebSocket മെസ്സേജ് എന്നിവയെല്ലാം ഇതിൽ ഉൾപ്പെടുന്നു. ഇവയെല്ലാം ഒരേ useEffect അല്ലെങ്കിൽ ഇവന്റ് ഹാൻഡ്ലറിലൂടെ കടന്നുപോകുന്നു, setState-ലൂടെ പ്രോസസ്സ് ചെയ്യപ്പെടുന്നു, ഒരേപോലെ തോന്നിക്കുന്നു. എന്നാൽ ഈ ഏകത ഒരു കെണിയാണ്. ഒരു യഥാർത്ഥ ആപ്ലിക്കേഷനിൽ എല്ലാ അസിൻക്രണസ് പ്രവർത്തനങ്ങളും ഒരേപോലെയല്ല. അവയെല്ലാം ഒരേപോലെയാണെന്ന് കരുതുന്നത് നിങ്ങളുടെ UI കോമ്പനന്റുകളെ useEffect ഹുക്കുകൾ ഉപയോഗിച്ച് താൽക്കാലികമായി കൂട്ടിച്ചേർക്കപ്പെട്ട, അപ്രതീക്ഷിതമായി സംഭവിക്കുന്ന കാര്യങ്ങളെ മാത്രം ആശ്രയിക്കുന്ന ഡാറ്റാ ആർക്കിടെക്റ്റുകളാക്കി മാറ്റുന്നു.
അസിൻക്രണസ് പ്രവർത്തനങ്ങളെ യഥാർത്ഥത്തിൽ മൂന്ന് വ്യത്യസ്ത വിഭാഗങ്ങളായി തിരിക്കാം. അവ ഓരോന്നിനും സമയം, കാഷിംഗ് (caching), ഉടമസ്ഥാവകാശം (ownership) എന്നിവയുമായി വ്യത്യസ്തമായ ബന്ധമാണുള്ളത്. ഇവയെ തിരിച്ചറിയാൻ പഠിക്കുന്നത് ഒരു ഫ്രണ്ട്എൻഡ് വേഗത്തിലും കൃത്യമായും സുഗമമായും പ്രവർത്തിപ്പിക്കാൻ സഹായിക്കുന്നു.
Queries: ഒരു വിലാസമുള്ള വസ്തുതകൾ (Facts with an Address)
ഒരു ക്വറി (query) എന്നത് വെറുമൊരു ഫെച്ച് (fetch) മാത്രമല്ല. അത് തിരിച്ചറിയാൻ കഴിയുന്ന ഒരു വസ്തുതയ്ക്കായുള്ള അഭ്യർത്ഥനയാണ്. നിങ്ങൾ ചോദിക്കുന്നത് /user/123 എന്നതിനെക്കുറിച്ചാണ്, അല്ലാതെ "ചില യൂസർ ഡാറ്റയെ" കുറിച്ചല്ല. ഈ വ്യത്യാസം പ്രധാനമാണ്, കാരണം ഐഡന്റിറ്റി (identity) ആണ് കാഷിംഗ് സാധ്യമാക്കുന്നത്. ഒരേ സ്ക്രീനിലെ രണ്ട് കോമ്പനന്റുകൾക്ക് ഒരേ യൂസർ റെക്കോർഡ് ആവശ്യമുണ്ടെങ്കിൽ, അവർ ഒരേ ഉത്തരം പങ്കിടണം. ഓരോ കോമ്പനന്റും useState-ൽ സ്വന്തം ലോക്കൽ കോപ്പി സൂക്ഷിക്കുമ്പോൾ, നിങ്ങൾ വിവരങ്ങളെ വിഘടിപ്പിക്കുന്നു. ഹെഡറിലെ അവതാറും സൈഡ്ബാറിലെ പേരും തമ്മിൽ വ്യത്യാസങ്ങൾ വരാൻ കാരണം അവ വ്യത്യസ്ത സമയങ്ങളിൽ ഫെച്ച് ചെയ്തതോ, അല്ലെങ്കിൽ ഒന്ന് വിജയിക്കുകയും മറ്റൊന്ന് പരാജയപ്പെടുകയോ ചെയ്തതോ ആകാം.
ഒരു ക്വറിയെ ഒരു ആക്ഷൻ എന്നതിലുപരി ഒരു റിസോഴ്സ് (resource) ആയി കാണുക. അതിന് ഒരു കാഷ് കീ (cache key), ഫ്രഷ്നസ് പോളിസി (freshness policy), കൂടാതെ ഏതൊരു കോമ്പനന്റിനേക്കാളും കൂടുതൽ കാലം നിലനിൽക്കുന്ന ഒരു ലൈഫ്സൈക്കിൾ എന്നിവയുണ്ട്. /projects?page=2 വായിക്കുന്നത് /projects?page=3 വായിക്കുന്നതിൽ നിന്ന് വ്യത്യസ്തമാണെന്ന് ഒരു നല്ല ക്വറി ലെയറിന് മനസ്സിലാകും. ഓരോ URL-ഉം പാരാമീറ്റർ സെറ്റും ഒരു വിലാസം (address) രൂപീകരിക്കുന്നു, ആ വിലാസത്തിലെ ഡാറ്റ പഴയതോ, പുതിയതോ അല്ലെങ്കിൽ ലഭ്യമല്ലാത്തതോ ആകാം. ഈ കണക്കുപുസ്തകങ്ങൾ കൈകാര്യം ചെയ്യേണ്ടത് UI-യുടെ ജോലിയല്ല. അത് ഡാറ്റാ ലെയറിനോട് user:123 ആവശ്യപ്പെടുകയും ഒരു സ്നാപ്പ്ഷോട്ട് (snapshot) സ്വീകരിക്കുകയും വേണം. ആ സ്നാപ്പ്ഷോട്ട് രണ്ട് സെക്കൻഡ് മുമ്പ് സെർവറിൽ നിന്നോ അല്ലെങ്കിൽ രണ്ട് മില്ലിസെക്കൻഡ് മുമ്പ് കാഷിൽ നിന്നോ വന്നതാണോ എന്നത് കോമ്പനന്റിനെ സംബന്ധിച്ചിടത്തോളം പ്രസക്തമല്ല.
ഇതിന്റെ പ്രായോഗിക പ്രത്യാഘാതം പെട്ടെന്നുതന്നെ അനുഭവപ്പെടും. ഓരോ റീഡും (read) ഒരു കോമ്പനന്റിനുള്ളിലെ ഇംപെറേറ്റീവ് ഫെച്ച് (imperative fetch) ആയി പരിഗണിക്കുമ്പോൾ, നിങ്ങൾക്ക് ഡ്യൂപ്ലിക്കേഷൻ ഒഴിവാക്കാനുള്ള (deduplication) കഴിവ് നഷ്ടപ്പെടുന്നു. ബാക്ക്ഗ്രൗണ്ട് റിഫ്രഷ് (background refresh) നഷ്ടപ്പെടുന്നു. ബാക്ക്ഗ്രൗണ്ടിൽ ഡാറ്റ പരിശോധിക്കുമ്പോൾ തന്നെ കാഷിലുള്ള ഡാറ്റ ഉടൻ കാണിക്കാനുള്ള കഴിവും നഷ്ടപ്പെടുന്നു. ഒരു ക്വറിക്ക് നിങ്ങളുടെ UI ട്രീക്ക് പുറത്ത് ഒരു സ്ഥാനം ആവശ്യമാണ്.
Mutations: ലോകത്തെ മാറ്റുക (Changing the World)
ക്വറികൾ ലോകത്തെക്കുറിച്ച് ചോദിക്കുമ്പോൾ, മ്യൂട്ടേഷനുകൾ (mutations) ലോകത്തെ മാറ്റുന്നു. യഥാർത്ഥ നെറ്റ്വർക്ക് റിക്വസ്റ്റ്—POST, PUT, അല്ലെങ്കിൽ DELETE—സാധാരണയായി എളുപ്പമുള്ള ഭാഗമാണ്. എന്നാൽ സെർവർ "OK" എന്ന് പറഞ്ഞതിന് ശേഷം സംഭവിക്കുന്ന കാര്യങ്ങളാണ് പ്രയാസമേറിയത്.
ഒരു ഉപയോക്താവ് അവരുടെ ഡിസ്പ്ലേ പേര് മാറ്റുന്നു എന്ന് കരുതുക. മ്യൂട്ടേഷൻ എന്നത് ഒരു സിംഗിൾ റിക്വസ്റ്റ് മാത്രമാണ്. എന്നാൽ അതിന്റെ ആഘാതം എല്ലായിടത്തും ഉണ്ടാകുന്നു. പ്രൊഫൈൽ പേജിൽ പഴയ പേര് കാണിക്കുന്നു. നാവിഗേഷൻ ബാറിൽ പഴയ പേര് കാണിക്കുന്നു. കമന്റ് ഹിസ്റ്ററിയിൽ അത് പരാമർശിച്ചേക്കാം. നിങ്ങളുടെ മ്യൂട്ടേഷൻ കോഡ് ഒരു ലോക്കൽ isLoading ഫ്ലാഗ് മാറ്റുന്നതിനും ഒരു സ്റ്റേറ്റ് അപ്ഡേറ്റ് ചെയ്യുന്നതിനും മാത്രം പരിമിതമാണെങ്കിൽ, നിങ്ങളുടെ ആപ്ലിക്കേഷൻ സ്വയം കള്ളം പറയുകയാണ്. UI-യുടെ ചില ഭാഗങ്ങൾ മാറ്റം സംഭവിച്ചതായി കാണിക്കുന്നു, എന്നാൽ മറ്റു ചില ഭാഗങ്ങൾക്ക് മാറ്റം സംഭവിച്ച വിവരം പോലും അറിയില്ല.
ഒരു മ്യൂട്ടേഷൻ ഡാറ്റ ഗ്രാഫിലുള്ള അതിന്റെ സ്വാധീനം പ്രഖ്യാപിക്കണം. ഏതെല്ലാം ക്വറികളാണ് ഇപ്പോൾ ഇൻവാലിഡ് (invalid) ആയതെന്നും, ഏതെല്ലാം കാഷ് കീകൾ വീണ്ടും ഫെച്ച് (refetch) ചെയ്യണമെന്നും, ഏതെല്ലാം ബന്ധങ്ങൾ മാറിയെന്നും അത് സിസ്റ്റത്തോട് പറയണം. ഇത് ഒരു ക്വറിയിൽ നിന്ന് അടിസ്ഥാനപരമായി വ്യത്യസ്തമാണ്. ഒരു ക്വറി റീഡ്-ഒൺലി (read-only) ആണ്, അത് പങ്കിടാൻ സാധിക്കും. എന്നാൽ ഒരു മ്യൂട്ടേഷൻ റൈറ്റ്-ഫോക്കസ്ഡ് (write-focused) ആണ്, അത് നിലവിലുള്ള കാഷുകളെ നശിപ്പിക്കുന്നു. ഇവ രണ്ടിനെയും ഒരേ രീതിയിൽ കാണുന്നത് വഴി ഡെവലപ്പർമാർ കോമ്പനന്റുകൾക്കുള്ളിൽ മാനുവലായി refetch() വിളിക്കേണ്ടി വരുന്നു, അല്ലെങ്കിൽ ലോക്കൽ സ്റ്റേറ്റ് സെർവറുമായി സിങ്ക് (sync) ചെയ്യാൻ useEffect ഹുക്കുകൾ ഉപയോഗിക്കേണ്ടി വരുന്നു.
ഉടമസ്ഥാവകാശ മാതൃകയും (ownership model) വ്യത്യസ്തമാണ്. ക്വറികൾ സാധാരണയായി കാഷാവിഭാവനത്തിന് (cache) കീഴിലാണ്. എന്നാൽ ഒരു മ്യൂട്ടേഷൻ അത് പ്രേരിപ്പിച്ച യൂസർ ആക്ഷന്റെ ഉടമസ്ഥതയിലാണ്. അതിന് ഒരു പെൻഡിംഗ് സ്റ്റേറ്റ് (pending state), ഒരു എറർ സ്റ്റേറ്റ് (error state), കൂടാതെ റോളുകൾ ചെയ്യേണ്ട ഒരു ഒപ്റ്റിമിസ്റ്റിക് വാല്യൂ (optimistic value) ഉണ്ടാകാൻ സാധ്യതയുമുണ്ട്.
