ਜ਼ਿਆਦਾਤਰ ਫਰੰਟਐਂਡ ਕੋਡ ਅਸਿੰਕਰੋਣ (asynchronous) ਕੰਮ ਨੂੰ ਇੱਕੋ ਜਿਹੀ ਸ਼ਕਲ ਵਜੋਂ ਮੰਨਦਾ ਹੈ। ਤੁਸੀਂ ਇੱਕ Promise ਸ਼ੁਰੂ ਕਰਦੇ ਹੋ, ਇਸਦੇ resolve ਹੋਣ ਦੀ ਉਡੀਕ ਕਰਦੇ ਹੋ, ਨਤੀਜੇ ਨੂੰ local state ਵਿੱਚ ਪਾ ਦਿੰਦੇ ਹੋ, ਅਤੇ ਫਰੇਮਵਰਕ ਨੂੰ diff ਨੂੰ reconcile ਕਰਨ ਦਿੰਦੇ ਹੋ। ਇਹ ਪੈਟਰਨ ਲੜਭਾਊ ਹੈ ਕਿਉਂਕਿ ਇਹ ਹਰ ਜਗ੍ਹਾ ਕੰਮ ਕਰਦਾ ਹੈ: ਇੱਕ REST call, ਇੱਕ ਫਾਰਮ submission, ਜਾਂ ਇੱਕ WebSocket message। ਉਹ ਸਾਰੇ ਇੱਕੋ useEffect ਜਾਂ event handler ਵਿੱਚ ਆਉਂਦੇ ਹਨ, ਸਾਰੇ setState ਰਾਹੀਂ ਪਾਈਪਲਾਈਨ ਕੀਤੇ ਜਾਂਦੇ ਹਨ, ਅਤੇ ਸਾਰੇ ਇੱਕੋ ਜਿਹੇ async plumbing ਵਾਂਗ ਦਿਖਾਈ ਦਿੰਦੇ ਹਨ। ਇਹ ਇਕਸਾਰਤਾ ਇੱਕ ਜਾਲ ਹੈ। ਇੱਕ ਅਸਲ ਐਪਲੀਕੇਸ਼ਨ ਵਿੱਚ, ਸਾਰਾ ਅਸਿੰਕਰੋਣ ਕੰਮ ਇੱਕੋ ਜਿਹਾ ਨਹੀਂ ਹੁੰਦਾ। ਅਜਿਹਾ ਦਿਖਾਵਾ ਕਰਨਾ ਕਿ ਇਹ ਇੱਕੋ ਜਿਹਾ ਹੈ, ਤੁਹਾਡੇ UI components ਨੂੰ ਅਣਜਾਣੇ ਵਿੱਚ data architects ਬਣਾ ਦਿੰਦਾ ਹੈ, ਜੋ useEffect hooks ਅਤੇ ਕਿਸਮਤ ਦੇ ਭਰੋਸੇ 'ਤੇ ਜੋੜੇ ਗਏ ਹਨ।

ਅਸਿੰਕਰੋਣ (Async) ਆਪਰੇਸ਼ਨ ਅਸਲ ਵਿੱਚ ਤਿੰਨ ਵੱਖ-ਵੱਖ ਕਿਸਮਾਂ ਵਿੱਚ ਵੰਡੇ ਹੋਏ ਹਨ। ਹਰ ਇੱਕ ਦਾ ਸਮੇਂ, caching, ਅਤੇ ਮਾਲਕੀ (ownership) ਨਾਲ ਵੱਖਰਾ ਰਿਸ਼ਤਾ ਹੁੰਦਾ ਹੈ। ਉਹਨਾਂ ਵਿੱਚ ਅੰਤਰ ਕਰਨਾ ਸਿੱਖਣਾ ਹੀ ਫਰੰਟਐਂਡ ਨੂੰ ਤੇਜ਼, ਸਹੀ ਅਤੇ ਸਥਿਰ ਰੱਖਦਾ ਹੈ।

Queries: ਇੱਕ ਪਤੇ ਵਾਲੇ ਤੱਥ

ਇੱਕ query ਸਿਰਫ਼ ਇੱਕ fetch ਨਹੀਂ ਹੈ। ਇਹ ਇੱਕ ਪਛਾਣਨਯੋਗ ਤੱਥ ਲਈ ਬੇਨਤੀ ਹੈ। ਤੁਸੀਂ /user/123 ਮੰਗ ਰਹੇ ਹੋ, ਨਾ ਕਿ "ਕੁਝ ਯੂਜ਼ਰ ਡੇਟਾ।" ਇਹ ਅੰਤਰ ਮਹੱਤਵਪੂਰਨ ਹੈ ਕਿਉਂਕਿ ਪਛਾਣ (identity) ਹੀ caching ਨੂੰ ਸੰਭਵ ਬਣਾਉਂਦੀ ਹੈ। ਜੇਕਰ ਇੱਕੋ ਸਕ੍ਰੀਨ 'ਤੇ ਦੋ components ਨੂੰ ਇੱਕੋ ਯੂਜ਼ਰ ਰਿਕਾਰਡ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਉਹਨਾਂ ਨੂੰ ਇੱਕ ਹੀ ਜਵਾਬ ਸਾਂਝਾ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ। ਜਦੋਂ ਹਰੇਕ component useState ਵਿੱਚ ਆਪਣੀ ਲੋਕਲ ਕਾਪੀ ਰੱਖਦਾ ਹੈ, ਤਾਂ ਤੁਸੀਂ ਆਪਣੀ ਸੱਚਾਈ ਨੂੰ ਖੰਡਿਤ ਕਰ ਦਿੰਦੇ ਹੋ। ਹੈਡਰ ਵਿੱਚ ਅਵਤਾਰ ਅਤੇ ਸਾਈਡਬਾਰ ਵਿੱਚ ਨਾਮ ਵੱਖਰੇ ਹੋ ਜਾਂਦੇ ਹਨ ਕਿਉਂਕਿ ਉਹ ਵੱਖ-ਵੱਖ ਸਮੇਂ 'ਤੇ fetch ਕੀਤੇ ਗਏ ਸਨ, ਜਾਂ ਇੱਕ ਅਸਫਲ ਰਿਹਾ ਜਦੋਂ ਕਿ ਦੂਜਾ ਸਫਲ ਹੋ ਗਿਆ।

ਇੱਕ query ਨੂੰ ਇੱਕ resource ਵਜੋਂ ਸੋਚੋ, ਨਾ ਕਿ ਇੱਕ action ਵਜੋਂ। ਇਸਦਾ ਇੱਕ cache key, ਇੱਕ freshness policy, ਅਤੇ ਇੱਕ lifecycle ਹੁੰਦਾ ਹੈ ਜੋ ਕਿਸੇ ਵੀ ਸਿੰਗਲ component ਤੋਂ ਵੱਧ ਸਮੇਂ ਤੱਕ ਰਹਿੰਦਾ ਹੈ। ਇੱਕ ਚੰਗੀ ਤਰ੍ਹਾਂ ਬਣਿਆ query layer ਸਮਝਦਾ ਹੈ ਕਿ /projects?page=2 ਨੂੰ ਪੜ੍ਹਨਾ /projects?page=3 ਨੂੰ ਪੜ੍ਹਨ ਨਾਲੋਂ ਵੱਖਰਾ ਹੈ। ਹਰੇਕ URL ਅਤੇ parameter set ਇੱਕ ਪਤਾ (address) ਬਣਾਉਂਦਾ ਹੈ, ਅਤੇ ਉਸ ਪਤੇ 'ਤੇ ਡੇਟਾ ਪੁਰਾਣਾ (stale), ਤਾਜ਼ਾ (fresh), ਜਾਂ ਗੁੰਮ ਹੋ ਸਕਦਾ ਹੈ। UI ਨੂੰ ਇਹ ਬੁੱਕਕੀਪਿੰਗ ਨਹੀਂ ਕਰਨੀ ਚਾਹੀਦੀ। ਇਸਨੂੰ data layer ਤੋਂ user:123 ਮੰਗਣਾ ਚਾਹੀਦਾ ਹੈ ਅਤੇ ਇੱਕ snapshot ਪ੍ਰਾਪਤ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ। ਚਾਹੇ ਉਹ snapshot ਦੋ ਸਕਿੰਟ ਪਹਿਲਾਂ ਸਰਵਰ ਤੋਂ ਆਇਆ ਹੋਵੇ ਜਾਂ ਦੋ ਮਿਲੀਸਕਿੰਟ ਪਹਿਲਾਂ cache ਤੋਂ, ਇਸ ਨਾਲ component ਦਾ ਕੋਈ ਲੈਣਾ-ਦੇਣਾ ਨਹੀਂ ਹੈ।

ਇਸਦਾ ਵਿਹਾਰਕ ਪ੍ਰਭਾਵ ਤੁਰੰਤ ਹੁੰਦਾ ਹੈ। ਜਦੋਂ ਤੁਸੀਂ ਹਰ read ਨੂੰ component ਦੇ ਅੰਦਰ ਇੱਕ imperative fetch ਵਜੋਂ ਮੰਨਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ deduplication ਗੁਆ ਲੈਂਦੇ ਹੋ। ਤੁਸੀਂ background refresh ਗੁਆ ਲੈਂਦੇ ਹੋ। ਤੁਸੀਂ background ਵਿੱਚ ਵੈਲੀਡੇਸ਼ਨ ਕਰਦੇ ਹੋਏ ਤੁਰੰਤ cached data ਦਿਖਾਉਣ ਦੀ ਸਮਰੱਥਾ ਗੁਆ ਲੈਂਦੇ ਹੋ। ਇੱਕ query ਤੁਹਾਡੇ UI tree ਤੋਂ ਬਾਹਰ ਇੱਕ ਘਰ ਦੀ ਹੱਕਦਾਰ ਹੈ।

Mutations: ਦੁਨੀਆ ਨੂੰ ਬਦਲਣਾ

ਜੇਕਰ queries ਦੁਨੀਆ ਬਾਰੇ ਪੁੱਛਦੀਆਂ ਹਨ, ਤਾਂ mutations ਇਸਨੂੰ ਬਦਲਦੀਆਂ ਹਨ। ਅਸਲ network request—POST, PUT, ਜਾਂ DELETE—ਆਮ ਤੌਰ 'ਤੇ ਸੌਖਾ ਹਿੱਸਾ ਹੁੰਦਾ ਹੈ। ਔਖਾ ਹਿੱਸਾ ਉਹ ਸਭ ਕੁਝ ਹੈ ਜੋ ਸਰਵਰ ਦੇ "OK" ਕਹਿਣ ਤੋਂ ਬਾਅਦ ਹੁੰਦਾ ਹੈ।

ਮੰਨ ਲਓ ਕਿ ਇੱਕ ਯੂਜ਼ਰ ਆਪਣਾ display name ਅਪਡੇਟ ਕਰਦਾ ਹੈ। Mutation ਆਪਣੇ ਆਪ ਵਿੱਚ ਇੱਕ ਸਿੰਗਲ ਰਿਕੁਐਸ ਹੈ। ਪਰ ਇਸਦਾ ਪ੍ਰਭਾਵ (blast radius) ਹਰ ਪਾਸੇ ਹੁੰਦਾ ਹੈ। ਪ੍ਰੋਫਾਈਲ ਪੇਜ 'ਤੇ ਪੁਰਾਣਾ ਨਾਮ ਹੈ। ਨੈਵੀਗੇਸ਼ਨ ਬਾਰ ਪੁਰਾਣਾ ਨਾਮ ਦਿਖਾ ਰਿਹਾ ਹੈ। ਕਮੈਂਟ ਹਿਸਟਰੀ ਇਸਦਾ ਹਵਾਲਾ ਦੇ ਸਕਦੀ ਹੈ। ਜੇਕਰ ਤੁਹਾਡਾ mutation code ਇੱਕ ਲੋਕਲ isLoading ਫਲੈਗ ਨੂੰ ਬਦਲਣ ਅਤੇ ਫਿਰ ਸਟੇਟ ਦੇ ਇੱਕ ਹਿੱਸੇ ਨੂੰ ਅਪਡੇਟ ਕਰਨ ਤੋਂ ਇਲਾਵਾ ਕੁਝ ਨਹੀਂ ਕਰਦਾ ਹੈ, ਤਾਂ ਤੁਹਾਡੀ ਐਪਲੀਕੇਸ਼ਨ ਹੁਣ ਆਪਣੇ ਆਪ ਨਾਲ ਝੂਠ ਬੋਲ ਰਹੀ ਹੈ। UI ਦੇ ਕੁਝ ਹਿੱਸੇ ਦਿਖਾਵਾ ਕਰਦੇ ਹਨ ਕਿ ਬਦਲਾਅ ਹੋ ਗਿਆ ਹੈ। ਦੂਜਿਆਂ ਨੂੰ ਪਤਾ ਹੀ ਨਹੀਂ ਹੁੰਦਾ ਕਿ ਕੁਝ ਬਦਲਿਆ ਹੈ।

ਇੱਕ mutation ਨੂੰ data graph 'ਤੇ ਆਪਣੇ ਪ੍ਰਭਾਵ ਨੂੰ ਘੋਸ਼ਿਤ ਕਰਨਾ ਚਾਹੀਦਾ ਹੈ। ਇਸਨੂੰ ਸਿਸਟਮ ਨੂੰ ਦੱਸਣਾ ਚਾਹੀਦਾ ਹੈ ਕਿ ਕਿਹੜੀਆਂ queries ਹੁਣ invalid ਹਨ, ਕਿਹੜੀਆਂ cached keys ਨੂੰ ਮੁੜ fetch ਕਰਨ ਦੀ ਲੋੜ ਹੈ, ਅਤੇ ਕਿਹੜੇ ਰਿਸ਼ਤੇ ਬਦਲ ਗਏ ਹਨ। ਇਹ ਮੂਲ ਰੂਪ ਵਿੱਚ ਇੱਕ query ਤੋਂ ਵੱਖਰਾ ਹੈ। ਇੱਕ query read-only ਅਤੇ shareable ਹੁੰਦੀ ਹੈ। ਇੱਕ mutation write-focused ਹੁੰਦੀ ਹੈ ਅਤੇ ਮੌਜੂਦਾ caches ਲਈ ਵਿਨਾਸ਼ਕਾਰੀ ਹੁੰਦੀ ਹੈ। ਉਹਨਾਂ ਨੂੰ ਇੱਕੋ ਅਬਸਟਰੈਕਸ਼ਨ (abstraction) ਵਿੱਚ ਮਿਲਾਉਣ ਦਾ ਮਤਲਬ ਹੈ ਕਿ ਡਿਵੈਲਪਰਾਂ ਨੂੰ ਰੈਂਡਮ components ਦੇ ਅੰਦਰ ਮੈਨੂਅਲੀ refetch() ਕਾਲ ਕਰਨਾ ਪੈਂਦਾ ਹੈ, ਜਾਂ ਇਸ ਤੋਂ ਵੀ ਮਾੜਾ, ਸਰਵਰ ਨਾਲ ਸਥਿਤੀ ਨੂੰ "sync" ਕਰਨ ਲਈ tree ਵਿੱਚ useEffect hooks ਬਿਖੇਰਨੇ ਪੈਂਦੇ ਹਨ।

ਮਾਲਕੀ ਮਾਡਲ (ownership model) ਵੀ ਵੱਖਰਾ ਹੈ। Queries ਆਮ ਤੌਰ 'ਤੇ cache ਦੁਆਰਾ ਮਾਲਕ ਬਣਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ। ਇੱਕ mutation ਉਸ ਯੂਜ਼ਰ ਐਕਸ਼ਨ ਦੁਆਰਾ ਮਾਲਕ ਹੁੰਦੀ ਹੈ ਜਿਸਨੇ ਇਸਨੂੰ ਟ੍ਰਿਗਰ ਕੀਤਾ ਹੈ। ਇਸਦੀ ਇੱਕ pending state, ਇੱਕ error state, ਅਤੇ ਸੰਭਾਵੀ ਤੌਰ 'ਤੇ ਇੱਕ optimistic value ਹੁੰਦੀ ਹੈ ਜਿਸ ਨੂੰ ਰੋਲ ਕਰਨ ਦੀ ਲੋੜ ਹੈ