ਸਟੇਟ ਮੈਨੇਜਮੈਂਟ ਔਖਾ ਹੈ ਕਿਉਂਕਿ ਐਪ ਬਹੁਤ ਸਾਰੇ ਸਰੋਤ-ਏ-ਸੱਚ, ਐਸਿੰਕ ਡਾਟਾ, UI ਇੰਟਰੈਕਸ਼ਨ ਅਤੇ ਪ੍ਰਦਰਸ਼ਨ ਟਰੇਡ‑ਆਫ਼ ਨਾਲ ਨਿਭਾਉਂਦੇ ਹਨ। ਕੀੜਿਆਂ ਨੂੰ ਘਟਾਉਣ ਲਈ ਪੈਟਰਨ ਸਿੱਖੋ।

ਫਰੰਟਏਂਡ ਐਪ ਵਿੱਚ, ਸਟੇਟ ਸਿਰਫ਼ ਉਹ ਡਾਟਾ ਹੈ ਜਿਸ 'ਤੇ ਤੁਹਾਡੀ UI ਨਿਰਭਰ ਹੁੰਦੀ ਹੈ ਅਤੇ ਜੋ ਵਕਤ ਦੇ ਨਾਲ ਬਦਲ ਸਕਦਾ ਹੈ।
ਜਦੋਂ ਸਟੇਟ ਬਦਲਦੀ ਹੈ ਤਾਂ ਸਕਰੀਨ ਨੂੰ ਵੀ ਉਸ ਦੇ ਅਨੁਸਾਰ ਅਪਡੇਟ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ। ਜੇ ਸਕਰੀਨ ਅਪਡੇਟ ਨਹੀਂ ਹੁੰਦੀ, ਅਸਮਰੱਥੀ ਨਾਲ ਅਪਡੇਟ ਹੁੰਦੀ ਹੈ, ਜਾਂ ਪੁਰਾਣੇ ਅਤੇ ਨਵੇਂ ਵੈਲਯੂਜ਼ ਮਿਕਸ ਹੋਕੇ ਦਿਖਾਈ ਦਿੰਦੇ ਹਨ, ਤਾਂ ਤੁਸੀਂ ਤੁਰੰਤ “ਸਟੇਟ ਸਮੱਸਿਆ” ਮਹਿਸੂਸ ਕਰੋਗੇ—ਬਟਨ ਜੋ ਡਿਸੇਬਲ ਰਹਿ ਜਾਂਦੇ ਹਨ, ਟੋਟਲ ਮਿਲਦੇ ਨਹੀਂ, ਜਾਂ ਵਿਊ ਉਹ ਨਹੀਂ ਦਿਖਾਉਂਦੀ ਜੋ ਉਪਭੋਗਤਾ ਨੇ ਹਾਲ ਹੀ ਵਿੱਚ ਕੀਤਾ ਸੀ।
ਸਟੇਟ ਛੋਟੇ ਅਤੇ ਵੱਡੇ ਇੰਟਰਐਕਸ਼ਨਾਂ ਦੋਹਾਂ ਵਿੱਚ ਆਉਂਦੀ ਹੈ, ਜਿਵੇਂ:
ਇਨਾਂ ਵਿੱਚੋਂ ਕੁਝ “ਅਸਥਾਈ” ਹਨ (ਜਿਵੇਂ ਚੁਣਿਆ ਹੋਇਆ ਟੈਬ), ਜਦਕਿ ਹੋਰ ਮਹੱਤਵਪੂਰਨ ਲੱਗਦੇ ਹਨ (ਜਿਵੇਂ ਕਾਰਟ)। ਇਹ ਸਾਰੇ ਸਟੇਟ ਹਨ ਕਿਉਂਕਿ ਇਹ ਅਸਰ ਕਰਦੇ ਹਨ ਕਿ UI ਇਹ ਵੇਲੇ ਕੀ ਰੇਂਡਰ ਕਰੇ।
ਇੱਕ ਸਧਾਰਨ ਵੈਰੀਏਬਲ ਸਿਰਫ ਉਸ ਥਾਂ ਲਈ ਮਹੱਤਵਪੂਰਨ ਹੁੰਦੀ ਹੈ ਜਿੱਥੇ ਇਹ ਰਹਿੰਦੀ ਹੈ। ਸਟੇਟ ਵੱਖ ਹੈ ਕਿਉਂਕਿ ਇਸ ਦੇ ਕੁਝ ਨਿਯਮ ਹੁੰਦੇ ਹਨ:
ਸਟੇਟ ਮੈਨੇਜਮੈਂਟ ਦਾ ਅਸਲ ਮਕਸਦ ਡਾਟਾ ਸਟੋਰ ਕਰਨਾ ਨਹੀਂ—ਬਲਕਿ ਅਪਡੇਟਾਂ ਨੂੰ ਭਰੋਸੇਯੋਗ ਬਣਾਉਣਾ ਹੈ ਤਾਂ ਕਿ UI ਸਥਿਰ ਰਹੇ। ਜਦੋਂ ਤੁਸੀਂ “ਕੀ ਬਦਲਿਆ, ਕਦੋਂ, ਤੇ ਕਿਉਂ” ਦਾ ਜਵਾਬ ਦੇ ਸਕਦੇ ਹੋ, ਤਾਂ ਸਟੇਟ ਸੰਭਾਲਣਯੋਗ ਬਣ ਜਾਂਦੀ ਹੈ। ਜਦੋਂ ਨਹੀਂ, ਤਾਂ ਆਸਾਨ ਫੀਚਰ ਵੀ ਅਚਾਨਕ ਮੁਸ਼ਕਲ ਹੋ ਸਕਦੇ ਹਨ।
ਆਰੰਭ ਵਿੱਚ, ਸਟੇਟ ਲਗਭਗ ਬੋਰਿੰਗ ਲੱਗਦੀ ਹੈ—ਚੰਗੇ ਤਰੀਕੇ ਨਾਲ। ਇਕ ਕੰਪੋਨੇਟ, ਇਕ ਇਨਪੁਟ, ਅਤੇ ਇਕ ਸਪੱਠ ਅਪਡੇਟ। ਯੂਜ਼ਰ ਫੀਲਡ ਵਿੱਚ ਟਾਈਪ ਕਰਦਾ ਹੈ, ਤੁਸੀਂ ਉਹ ਵੈਲਯੂ ਸੇਟ ਕਰਦੇ ਹੋ, ਅਤੇ UI ਰੀ-ਰੈਂਡਰ ਹੁੰਦਾ ਹੈ। ਹਰ ਚੀਜ਼ ਦਿੱਸਦੀ, ਤਤਕਾਲ ਅਤੇ ਸਮੇਤ ਹੈ।
ਕਲਪਨਾ ਕਰੋ ਇੱਕ ਸਾਦਾ ਟੈਕਸਟ ਇਨਪੁਟ ਜਿਸ ਦਾ ਪ੍ਰੀਵਿਊ ਦਿਖਾਉਂਦਾ ਹੈ ਜੋ ਤੁਸੀਂ ਟਾਈਪ ਕੀਤਾ:
ਇਸ ਸੈੱਟਅਪ ਵਿੱਚ, ਸਟੇਟ ਅਸਲ ਵਿੱਚ: ਵਕਤ ਦੇ ਨਾਲ ਬਦਲਣ ਵਾਲਾ ਇੱਕ ਵੈਰੀਏਬਲ ਹੈ। ਤੁਸੀਂ ਦੱਸ ਸਕਦੇ ਹੋ ਕਿ ਇਹ ਕਿੱਥੇ ਸਟੋਰ ਹੈ ਅਤੇ ਕਿੱਥੇ ਅਪਡੇਟ ਹੁੰਦਾ ਹੈ, ਅਤੇ ਕੰਮ ਮੁਕੰਮਲ।
ਲੋਕਲ ਸਟੇਟ ਕੰਮ ਕਰਦਾ ਹੈ ਕਿਉਂਕਿ ਮਾਨਸਿਕ ਮਾਡਲ ਕੋਡ ਢਾਂਚੇ ਨਾਲ ਮਿਲਦਾ ਹੈ:
ਅਜੇ ਵੀ ਜੇ ਤੁਸੀਂ React ਵਰਗਾ ਫਰੇਮਵਰਕ ਵਰਤਦੇ ਹੋ, ਤਾਂ ਗਤੀਸ਼ੀਲ ਤਰੀਕੇ ਬਾਰੇ ਸੋਚਣ ਦੀ ਲੋੜ ਘੱਟ ਹੁੰਦੀ ਹੈ। ਡਿਫੌਲਟ کافی ਹੁੰਦੇ ਹਨ।
ਜਿਵੇਂ ਹੀ ਐਪ "ਇੱਕ ਪੇਜ ਦੇ ਵਿਜਟ" ਤੋਂ "ਇੱਕ ਉਤਪਾਦ" ਬਣ ਜਾਂਦੀ ਹੈ, ਸਟੇਟ ਇਕ ਜਗ੍ਹਾ ਨਹੀਂ ਰਹਿੰਦੀ।
ਹੁਣ ਇੱਕੋ ਡੇਟਾ ਦੇ ਟੁਕੜੇ ਨੂੰ ਲੋੜ ਹੋ ਸਕਦੀ ਹੈ:
ਇੱਕ ਪ੍ਰੋਫ਼ਾਈਲ ਨਾਮ ਹੇਡਰ ਵਿੱਚ ਦਿਖ ਸਕਦਾ ਹੈ, ਸੈਟਿੰਗ ਪੇਜ 'ਚ ਐਡਿਟ ਕੀਤਾ ਜਾ ਸਕਦਾ है, ਤੇਜ਼ ਲੋਡਿੰਗ ਲਈ ਕੈਸ਼ ਕੀਤਾ ਜਾ ਸਕਦਾ ਹੈ, ਅਤੇ ਵੈਲਕਮ ਸੰਦੇਸ਼ ਵਿੱਚ ਪर्सਨਲਾਈਜ਼ੇਸ਼ਨ ਲਈ ਵਰਤਿਆ ਜਾ ਸਕਦਾ ਹੈ। ਅਚਾਨਕ ਸਵਾਲ ਇਹ ਨਹੀਂ ਰਹਿੰਦਾ ਕਿ “ਇਸ ਵੈਲਯੂ ਨੂੰ ਕਿੱਥੇ ਸਟੋਰ ਕੀਤਾ ਜਾਵੇ?”, ਸਗੋਂ “ਕਿਹੜੀ ਥਾਂ ਇਸਨੂੰ ਰੱਖਣੀ ਚਾਹੀਦੀ ਹੈ ਤਾਂ ਜੋ ਇਹ ਹਰ ਜਗ੍ਹਾ ਸਹੀ ਰਹੇ?”
ਸਟੇਟ ਦੀ ਜਟਿਲਤਾ ਫੀਚਰਾਂ ਨਾਲ ਧੀਰੇ-ਧੀਰੇ ਨਹੀਂ ਵਧਦੀ—ਇਹ ਕਦਮ ਵਧਦੀ ਹੈ।
ਦੂਜੇ ਸਥਾਨ ਤੇ ਉਹੀ ਡੇਟਾ ਪੜ੍ਹਨ ਦੀ ਲੋੜ ਪੈਣ ਨਾਲ ਮੁੱਦੇ ਆਉਂਦੇ ਹਨ: ਵਿਊਜ਼ ਨੂੰ ਮਿਲਾਉਣਾ, ਸਟੇਲ ਵੈਲਯੂਜ਼ ਨੂੰ ਰੋਕਣਾ, ਫੈਸਲਾ ਕਰਨਾ ਕਿ ਕਿਸਨੇ ਕਿਹੜੀ ਚੀਜ਼ ਅਪਡੇਟ ਕਰਨੀ ਹੈ, ਅਤੇ ਟਾਈਮਿੰਗ ਨੂੰ ਹੈਂਡਲ ਕਰਨਾ। ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਕੁਝ ਸਾਂਝੇ ਟੁਕੜੇ ਸਟੇਟ ਅਤੇ ਕੁਝ ਐਸਿੰਕ ਕੰਮ ਹੁੰਦੇ ਹਨ, ਤਾਂ ਵਿਹਾਰ ਅਜਿਹਾ ਹੋ ਸਕਦਾ ਹੈ ਜੋ ਸੋਚਣਾ ਮੁਸ਼ਕਲ ਕਰ ਦੇਵੇ—ਭਾਵੇਂ ਹਰ ਇਕ ਫੀਚਰ ਅਲੱਗ-ਅਲੱਗ ਸਾਦਾ ਹੀ ਲੱਗਦਾ ਹੋਵੇ।
ਸਟੇਟ ਤਕਲੀਫ਼ਦਾਇਕ ਹੁੰਦੀ ਹੈ ਜਦੋਂ ਇਕੋ “ਤਥ” ਕਈ ਥਾਂਵਾਂ ਤੇ ਸਟੋਰ ਹੋਵੇ। ਹਰ ਨੱਕਲ ਡ੍ਰਿਫਟ ਕਰ ਸਕਦੀ ਹੈ, ਅਤੇ ਹੁਣ ਤੁਹਾਡੀ UI ਆਪਸ ਵਿੱਚ ਵਾਦ-ਵਿਵਾਦ ਕਰ ਰਹੀ ਹੁੰਦੀ ਹੈ।
ਜ਼ਿਆਦਾਤਰ ਐਪ ਵਿੱਚ ਕਈ ਥਾਂਵਾਂ ਹੁੰਦੀਆਂ ਹਨ ਜੋ “ਸੱਚ” ਰੱਖ ਸਕਦੀਆਂ ਹਨ:
ਇਹ ਸਭ ਕੁਝ ਕਿਸੇ-ਨਾਮ ਦੀਂ ਸਥਿਤੀਆਂ ਲਈ ਠੀਕ ਮਾਲਿਕ ਹੋ ਸਕਦੇ ਹਨ। ਸਮੱਸਿਆ ਉਸ ਵੇਲੇ ਸ਼ੁਰੂ ਹੁੰਦੀ ਹੈ ਜਦੋਂ ਇਹ ਸਭ ਇਕੋ ਹੀ ਸਟੇਟ ਦਾ ਮਾਲਿਕ ਬਣਦੇ ਹਨ।
ਇੱਕ ਆਮ ਪੈਟਰਨ: ਸਰਵਰ ਡੇਟਾ ਫੇਚ ਕਰੋ, ਫਿਰ ਲੋਕਲ ਸਟੇਟ ਵਿੱਚ ਕਾਪੀ ਕਰੋ “ਤਾਂ ਜੋ ਅਸੀਂ ਸੰਪਾਦਨ ਕਰ ਸਕੀਏ।” ਉਦਾਹਰਨ ਵਜੋਂ, ਤੁਸੀਂ ਯੂਜ਼ਰ ਪ੍ਰੋਫ਼ਾਈਲ ਲੋਡ ਕਰਦੇ ਹੋ ਅਤੇ formState = userFromApi ਸੈੱਟ ਕਰਦੇ ਹੋ। ਬਾਅਦ ਵਿੱਚ ਸਰਵਰ ਰੀਫੇਚ ਕਰਦਾ ਹੈ (ਜਾਂ ਕੋਈ ਹੋਰ ਟੈਬ ਰਿਕਾਰਡ ਅਪਡੇਟ ਕਰਦਾ ਹੈ), ਹੁਣ ਤੁਹਾਡੇ ਕੋਲ ਦੋ ਵਰਜਨ ਹਨ: ਕੈਸ਼ ਵੱਖੋ ਇੱਕ ਚੀਜ਼ ਕਹਿੰਦੀ ਹੈ, ਤੁਹਾਡੀ ਫਾਰਮ ਦੂਜੀ।
ਨਕਲ ਆਮ ਤੌਰ 'ਤੇ “ਸਹਾਇਕ” ਪਰਿਵਰਤਨ ਰਾਹੀਂ ਵੀ ਆਉਂਦੀ ਹੈ: items ਅਤੇ itemsCount ਦੋਵੇਂ ਸਟੋਰ ਕਰਨਾ, ਜਾਂ selectedId ਅਤੇ selectedItem ਦੋਹਾਂ ਰੱਖਣਾ।
ਜਦੋਂ ਕਈ ਸਰੋਤ-ਏ-ਸੱਚ ਹੋਂਦੇ ਹਨ, ਤਦ ਬੱਗ ਆਮ ਤੌਰ ਤੇ ਇਸ ਤਰ੍ਹਾਂ ਹੁੰਦੇ ਹਨ:
ਹਰ ਇਕ ਸਟੇਟ ਦੀ ਇੱਕ ਮਾਲਕੀ (owner) ਚੁਣੋ—ਉਹ ਥਾਂ ਜਿੱਥੇ ਅਪਡੇਟ ਕੀਤੇ ਜਾਂਦੇ ਹਨ—ਅਤੇ ਹੋਰ ਸਭ ਕੁਝ ਇੱਕ ਪਰੋਜੈਕਸ਼ਨ ਵਜੋਂ ਲਓ (ਰੀਡ-ਓਨਲੀ, derived, ਜਾਂ ਇਕ ਦਿਸ਼ਾ ਵਿੱਚ ਸਿੰਕ ਕੀਤਾ)। ਜੇ ਤੁਸੀਂ ਮਾਲਕੀ ਦੱਸ ਨਹੀਂ ਸਕਦੇ, ਤਾਂ ਸੰਭਵ ਹੈ ਕਿ ਤੁਸੀਂ ਇੱਕੋ ਸੱਚ ਦੀ ਦੋਹਰੀ ਸਟੋਰੇਜ ਕਰ ਰਹੇ ਹੋ।
ਅਕਸਰ ਫਰੰਟਏਂਡ ਸਟੇਟ ਸਧਾਰਨ ਲੱਗਦੀ ਹੈ ਕਿਉਂਕਿ ਉਹ synchronous ਹੁੰਦੀ ਹੈ: ਯੂਜ਼ਰ ਕਲਿਕ ਕਰਦਾ ਹੈ, ਤੁਸੀਂ ਵੈਲਯੂ ਸੈੱਟ ਕਰਦੇ ਹੋ, UI ਅਪਡੇਟ ਹੁੰਦੀ ਹੈ। ਸਾਈਡ-ਇਫੈਕਟ ਉਸ ਸਾਫ਼ ਕਦਮ-ਦਰ ਕਦਮ ਕਹਾਣੀ ਨੂੰ ਤੋੜਦੇ ਹਨ।
ਸਾਈਡ-ਇਫੈਕਟ ਉਹ ਸਾਰੇ ਕੰਮ ਹਨ ਜੋ ਤੁਹਾਡੇ ਕੰਪੋਨੇਟ ਦੇ ਪਿਉਰੇ "ਰੇਂਡਰ ਆਧਾਰਿਤ ਡੇਟਾ" ਮਾਡਲ ਤੋਂ ਬਾਹਰ ਜਾ ਕੇ ਹੁੰਦੇ ਹਨ:
ਹਰ ਇਕ ਕਦੇ ਬਾਅਦ ਚੱਲ ਸਕਦਾ ਹੈ, ਅਸਫਲ ਹੋ ਸਕਦਾ ਹੈ, ਜਾਂ ਇੱਕ ਤੋਂ ਵਾਰੀ ਚੱਲ ਸਕਦਾ ਹੈ।
ਐਸਿੰਕ ਅਪਡੇਟ ਸਮੇਂ ਨੂੰ ਇੱਕ ਵੈਰੀਏਬਲ ਬਣਾਉਂਦੇ ਹਨ। ਹੁਣ ਤੁਸੀਂ "ਕੀ ਹੋਇਆ" ਦੀ ਬਜਾਏ "ਕੀ ਹੋ ਸਕਦਾ ਹੈ" ਦੀ ਸੋਚ ਕਰਦੇ ਹੋ। ਦੋ ਰਿਕਵੇਸਟ ਇਕਠੇ ਚੱਲ ਸਕਦੀਆਂ ਹਨ। ਇੱਕ ਧੀਮੀ ਰਿਸਪਾਂਸ ਨਵੇਂ ਵਾਲੇ ਤੋਂ ਬਾਅਦ ਆ ਸਕਦੀ ਹੈ। ਇੱਕ ਕੰਪੋਨੇਟ ਅਨਮਾਉਂਟ ਹੋ ਸਕਦਾ ਹੈ ਜਦਕਿ ਐਸਿੰਕ 콼ਬੈਕ ਹਜੇ ਵੀ ਸਟੇਟ ਅਪਡੇਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦਾ ਹੈ।
ਇਸ ਦੇ ਕਾਰਨ ਬੱਗ ਇੱਧੇ ਲੱਗਦੇ ਹਨ:
ਬਦਲੇ ਵਿੱਚ 바카라 booleans ਵਾਂਗ isLoading ਨੂੰ ਇੰਡਸਪ੍ਰੈਡ ਕਰਨ ਦੀ ਬਜਾਏ, ਐਸਿੰਕ ਕੰਮ ਨੂੰ ਇੱਕ ਛੋਟੀ state machine ਵਜੋਂ ਮਾਡਲ ਕਰੋ:
ਡੇਟਾ ਅਤੇ ਸਟੇਟਸ ਦੋਹਾਂ ਨੂੰ ਇਕੱਠੇ ਟਰੈਕ ਕਰੋ, ਅਤੇ ਇੱਕ ਪਛਾਣ ਵਾਲਾ (ਜਿਵੇਂ request id ਜਾਂ query key) ਰੱਖੋ ਤਾਂ ਜੋ ਤੁਹਾਡੇ ਕੋਲ ਦੇਰੀ ਨਾਲ ਆਈਆਂ ਜਵਾਬਾਂ ਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਨ ਦੀ ਯੋਜਨਾ ਹੋਵੇ। ਇਸ ਨਾਲ “ਹੁਣ UI ਨੂੰ ਕੀ ਦਿਖਾਉਣਾ ਚਾਹੀਦਾ ਹੈ?” ਦਾ ਫੈਸਲਾ ਸਪੱਠ ਹੋ ਜਾਵੇਗਾ ਨਾ ਕਿ ਅਟਕਲ।
ਬਹੁਤ ਸਾਰੇ ਸਟੇਟ ਮੁਸ਼ਕਲ ਇਹਨਾਂ ਦੇ ਮਿਸ਼ਰਣ ਨਾਲ ਸ਼ੁਰੂ ਹੁੰਦੇ ਹਨ: “ਉਹ ਜੋ ਯੂਜ਼ਰ ਹਾਲ ਹੀ ਵਿੱਚ ਕਰ ਰਿਹਾ ਹੈ” ਨੂੰ “ਜੋ ਬੈਕਐਂਡ ਦੱਸਦਾ ਹੈ” ਵਾਂਗੋਂ ਹੀ ਸਮਝ ਲੈਣਾ। ਦੋਹਾਂ ਸਮੇਂ ਦੇ ਨਾਲ ਬਦਲ ਸਕਦੇ ਹਨ, ਪਰ ਉਹ ਵੱਖਰੇ ਨਿਯਮਾਂ ਦੇ ਅਧୀਨ ਹੁੰਦੇ ਹਨ।
UI ਸਟੇਟ ਅਸਥਾਈ ਅਤੇ ਇੰਟਰਐਕਸ਼ਨ‑ਚੱਲਿਤ ਹੁੰਦੀ ਹੈ। ਇਹ ਸਕਰੀਨ ਨੂੰ ਇਸ ਤਰ੍ਹਾਂ ਰੇਂਡਰ ਕਰਨ ਲਈ ਮੌਜੂਦ ਹੈ ਜਿਵੇਂ ਯੂਜ਼ਰ ਉਮੀਦ ਕਰਦਾ ਹੈ ਇਸ ਪਲ।
ਉਦਾਹਰਨਾਂ: ਮੋਡਲ ਖੁੱਲਾ/ਬੰਦ, ਐਕਟਿਵ ਫਿਲਟਰ, ਖੋਜ ਇਨਪੁਟ ਦਾ ਡ੍ਰਾਫਟ, hover/focus, ਕਿਹੜਾ ਟੈਬ ਚੁਣਿਆ ਗਿਆ, pagination UI (ਮੌਜੂਦਾ ਪੇਜ਼, ਪੇਜ਼ ਸਾਈਜ਼, ਸਕ੍ਰੋਲ ਪੋਜ਼ੀਸ਼ਨ)।
ਇਹ ਸਟੇਟ ਆਮ ਤੌਰ 'ਤੇ ਇੱਕ ਪੇਜ਼ ਜਾਂ ਕੰਪੋਨੇਟ ਟ੍ਰੀ ਦੇ ਨਜ਼ਦੀਕੀ ਹੁੰਦੀ ਹੈ। ਇਹ ਠੀਕ ਹੈ ਕਿ ਜੇ ਤੁਸੀਂ ਨੈਵੀਗੇਟ ਕਰਕੇ ਦੂਰ ਹੋ ਜਾਓ ਤਾਂ ਇਹ ਰੀਸੈੱਟ ਹੋ ਜਾਵੇ।
ਸਰਵਰ ਸਟੇਟ API ਤੋਂ ਆਇਆ ਡੇਟਾ ਹੈ: ਯੂਜ਼ਰ ਪ੍ਰੋਫ਼ਾਈਲ, ਪ੍ਰੋਡਕਟ ਲਿਸਟ, ਪਰਮਿਸ਼ਨਾਂ, ਨੋਟੀਫਿਕੇਸ਼ਨ, ਸੇਵ ਕੀਤੀਆਂ ਸੈਟਿੰਗਜ਼। ਇਹ “ਰਿਮੋਟ ਟਰੂਥ” ਹੈ ਜੋ ਬਿਨਾਂ ਤੁਹਾਡੇ UI ਦੀ ਕੋਸ਼ਿਸ਼ ਦੇ ਵੀ ਬਦਲ ਸਕਦਾ ਹੈ (ਕੋਈ ਹੋਰ ਇਸਨੂੰ ਸੋਧਦਾ ਹੈ, ਸਰਵਰ ਦੁਬਾਰਾ ਗਣਨਾ ਕਰਦਾ ਹੈ, ਬੈਕਗ੍ਰਾਊਂਡ ਜੌਬ ਅਪਡੇਟ ਕਰਦਾ ਹੈ)।
ਕਿਉਂਕਿ ਇਹ ਰਿਮੋਟ ਹੈ, ਇਸਨੂੰ ਮੈਟਾਡੇਟਾ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ: ਲੋਡਿੰਗ/ਏਰਰ ਸਟੇਟ, ਕੈਸ਼ ਟਾਈਮਸਟੈਂਪ, ਰੀਟ੍ਰਾਈ, ਅਤੇ ਅਵੈਧ ਕਰਨ ਦੇ ਨਿਯਮ।
ਜੇ ਤੁਸੀਂ UI ਡ੍ਰਾਫਟਸ ਨੂੰ ਸਰਵਰ ਡੇਟਾ ਵਿੱਚ ਸਟੋਰ ਕਰਦੇ ਹੋ ਤਾਂ ਰੀਫੈਚ ਤੁਹਾਡੇ ਲੋਕਲ ਸੰਪਾਦਨਾਂ ਨੂੰ ਮਿਟਾ ਸਕਦਾ ਹੈ। ਜੇ ਤੁਸੀਂ ਸਰਵਰ ਰਿਸਪਾਂਸ ਨੂੰ UI ਸਟੇਟ ਵਿੱਚ ਬਿਨਾਂ ਕੈਸ਼ ਨਿਯਮ ਦੇ ਰੱਖਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਸਟੇਲ ਡੇਟਾ, ਡੁਪਲੀਕੇਟ ਫੈਚ, ਅਤੇ ਅਸਮਰੱਥ ਸਕ੍ਰੀਨਾਂ ਨਾਲ ਲੜ ਰਹੇ ਹੋਵੋਗੇ।
ਇੱਕ ਆਮ ਫੇਲ ਮੋਡ: ਯੂਜ਼ਰ ਫਾਰਮ ਸਪੱਸ਼ਲ ਕਰਦਾ ਹੈ ਜਦੋਂ ਪਿਛੋਕੜ ਰੀਫੈਚ ਖਤਮ ਹੋ ਜਾਂਦਾ ਹੈ, ਅਤੇ ਆਉਣ ਵਾਲੀ ਜਵਾਬ ਡ੍ਰਾਫਟ ਨੂੰ ਓਵਰਰਾਈਟ ਕਰ ਦਿੰਦੀ ਹੈ।
ਸਰਵਰ ਸਟੇਟ ਨੂੰ ਕੈਸ਼ ਕਰਨ ਵਾਲੇ ਪੈਟਰਨ ਨਾਲ ਸੰਭਾਲੋ (ਫੈਚ, ਕੈਸ਼, ਅਵੈਧ, ਫੋਕਸ ਉੱਤੇ ਰੀਫੈਚ) ਅਤੇ ਇਸਨੂੰ ਸਾਂਝਾ ਤੇ ਐਸਿੰਕ ਸਮਝੋ।
UI ਸਟੇਟ ਨੂੰ UI ਟੂਲਜ਼ ਨਾਲ ਸੰਭਾਲੋ (ਲੋਕਲ ਕੰਪੋਨੇਟ ਸਟੇਟ, ਉਹਨਾਂ UI ਮਾਮਲਿਆਂ ਲਈ context ਜਿੱਥੇ ਵਾਕਈ ਸਾਂਝਾ ਲੋੜ ਹੈ), ਅਤੇ ਡ੍ਰਾਫਟ ਨੂੰ ਅਲੱਗ ਰੱਖੋ ਜਦ ਤੱਕ ਤੁਸੀਂ ਜਾਣ-ਬੂਝ ਕੇ ਉਹਨੂੰ ਸਰਵਰ 'ਤੇ "ਸੇਵ" ਨਾ ਕਰੋ।
Derived state ਉਹ ਕੋਈ ਵੀ ਵੈਲਯੂ ਹੈ ਜੋ ਤੁਸੀਂ ਹੋਰ ਸਟੇਟ ਤੋਂ ਗਣਨਾ ਕਰ ਸਕਦੇ ਹੋ: ਕਾਰਟ ਟੋਟਲ ਲਾਈਨ ਆਈਟਮਾਂ ਤੋਂ, ਫਿਲਟਰ ਕੀਤੀ ਲਿਸਟ ਮੂਲ ਲਿਸਟ + ਖੋਜ ਕੁਇਰੀ ਤੋਂ, ਜਾਂ "canSubmit" ਫਲੈਗ ਫੀਲਡ ਵੈਲਿਊਜ਼ ਅਤੇ ਵੈਲिडੇਸ਼ਨ ਨਿਯਮਾਂ ਤੋਂ।
ਇਹਨੂੰ ਸਟੋਰ ਕਰਨਾ ਆਕਰਸ਼ਕ ਹੁੰਦਾ ਹੈ ਕਿਉਂਕਿ ਸਹੂਲਤ ਲੱਗਦੀ ਹੈ ("ਮੈਂ ਟੋਟਲ ਵੀ ਰੱਖ ਲੈਂਦਾ ਹਾਂ"). ਪਰ ਜਿਵੇਂ ਹੀ ਇਨਪੁੱਟ ਇਕ ਤੋਂ ਵੱਧ ਥਾਂ ਤੋਂ ਬਦਲਦੇ ਹਨ, ਤੁਸੀਂ ਡ੍ਰਿਫਟ ਦਾ ਖਤਰਾ ਲੈ ਲੈਂਦੇ ਹੋ: ਸਟੋਰ ਕੀਤਾ total ਆਈਟਮਾਂ ਨਾਲ ਮੇਲ ਨਹੀਂ ਖਾਂਦਾ, ਫਿਲਟਰਨੀ ਲਿਸਟ ਮੌਜੂਦਾ ਕੁਇਰੀ ਨੂੰ ਦਰਸਾਵੇ ਨਾ, ਜਾਂ ਸਬਮਿਟ ਬਟਨ ਗਲਤ ਤੌਰ 'ਤੇ ਡਿਸੇਬਲ ਰਹਿ ਜਾਵੇ। ਇਹ ਬੱਗ ਭੁੱਲਣ ਵਾਲੇ ਹੁੰਦੇ ਹਨ ਕਿਉਂਕਿ ਅਲੱਗ-ਅਲੱਗ ਸਟੇਟ ਵੈਰੀਏਬਲ ਆਪਣੇ ਆਪ ਵਿੱਚ ਠੀਕ ਲੱਗਦੇ ਹਨ—ਸਰਫ਼ ਇਕੱਠੇ ਨਹੀਂ।
ਸੁਰੱਖਿਅਤ ਪੈਟਰਨ ਇਹ ਹੈ: ਘੱਟੋ-ਘੱਟ ਸੌਰਸ-ਆਫ-ਟ੍ਰੂਥ ਸਟੋਰ ਕਰੋ, ਅਤੇ ਸਾਰਾ ਹੋਰ ਰੀਡ ਸਮੇਂ 'ਤੇ ਗਣਨਾ ਕਰੋ। React ਵਿੱਚ ਇਹ ਇੱਕ ਸਧਾਰਨ ਫੰਕਸ਼ਨ ਹੋ ਸਕਦਾ ਹੈ, ਜਾਂ memoized calculation।
const items = useCartItems();
const total = items.reduce((sum, item) => sum + item.price * item.qty, 0);
const filtered = products.filter(p => p.name.includes(query));
ਵੱਡੇ ਐਪ ਵਿੱਚ, "selectors" (ਯਾ computed getters) ਇਸ ਵਿਚਾਰ ਨੂੰ formalize ਕਰਦੇ ਹਨ: ਇੱਕ ਜਗ੍ਹਾ ਨਿਰਧਾਰਿਤ ਕਰਦੀ ਹੈ ਕਿ total, filteredProducts, visibleTodos ਕਿਵੇਂ ਨਿਕਲਦੇ ਹਨ, ਅਤੇ ਹਰ ਕੰਪੋਨੇਟ ਇਕੋ ਲਾਜ਼ਮ ਵਰਤਦਾ ਹੈ।
ਹਰ ਰੇਂਡਰ 'ਤੇ ਗਣਨਾ ਆਮ ਤੌਰ 'ਤੇ ਠੀਕ ਹੁੰਦੀ ਹੈ। ਉਸ ਵੇਲੇ ਕੈਸ਼ ਕਰੋ ਜਦੋਂ ਤੁਸੀਂ ਅਸਲ ਲਾਗਤ ਮਾਪੀ ਹੋਵੇ: ਮਹਿੰਗੇ ਟ੍ਰਾਂਸਫਾਰਮੇਸ਼ਨ, ਬਹੁਤ ਵੱਡੀਆਂ ਲਿਸਟਾਂ, ਜਾਂ derived values ਜੋ ਬਹੁਤ ਸਾਰੇ ਕੰਪੋਨੇਟਸ ਵਿੱਚ ਸਾਂਝੀਆਂ ਹੁੰਦੀਆਂ ਹਨ। memoization (useMemo, selector memoization) ਵਰਤੋ ਤਾਂ ਕਿ ਕੈਸ਼ ਕੀ-ਜ਼ ਠੀਕੇ ਇਨਪੁੱਟਸ ਤੇ ਆਧਾਰਿਤ ਹੋਣ—ਨਹੀਂ ਤਾਂ ਤੁਸੀਂ ਡ੍ਰਿਫਟ ਵਾਪਸ ਪ੍ਰਾਪਤ ਕਰ ਰਹੇ ਹੋ, ਸਿਰਫ ਪ੍ਰਦਰਸ਼ਨ ਨਾਂ ਹੋ ਕੇ।
ਸਟੇਟ ਤਦੋਂ ਪਰੇਸ਼ਾਨ ਕਰਨ ਵਾਲੀ ਬਣਦੀ ਹੈ ਜਦੋਂ ਇਹ ਅਸਪਸ਼ਟ ਹੋ ਕਿ ਕਿਸਦੀ ਮਾਲਕੀ ਹੈ।
ਕਿਸੇ ਸਟੇਟ ਦੀ ਮਾਲਕੀ ਉਹ ਥਾਂ ਹੈ ਜਿਸ ਨੂੰ ਇਸਨੂੰ ਅਪਡੇਟ ਕਰਨ ਦਾ ਹੱਕ ਹੈ। ਹੋਰ ਹਿੱਸੇ ਇਸਨੂੰ ਪੜ੍ਹ ਸਕਦੇ ਹਨ (props, context, selectors ਆਦਿ ਰਾਹੀਂ), ਪਰ ਉਹ ਸਿੱਧਾ ਇਸਨੂੰ ਨਹੀਂ ਬਦਲਣੇ ਚਾਹੀਦੇ।
ਸਪੱਸ਼ਟ ਮਾਲਕੀ ਦੋ ਸਵਾਲਾਂ ਦਾ ਜਵਾਬ ਦਿੰਦੀ ਹੈ:
ਜਦੋਂ ਇਹ ਸੀਮਾਵਾਂ ਧੁੰਦਲੀ ਹੋ ਜਾਂਦੀਆਂ ਹਨ, ਤੁਹਾਨੂੰ ਟਕਰਾਅ-ਅਪਡੇਟ, "ਇਹ ਕਿਉਂ ਬਦਲਿਆ" ਵਾਲੇ ਪਲ, ਅਤੇ ਮੁੜ-ਵਰਤੋਂ ਯੋਗ ਕੰਪੋਨੇਟਸ ਮਿਲਦੇ ਹਨ ਜੋ ਮੁਸ਼ਕਲ ਹੋ ਜਾਦੇ ਹਨ।
ਸਟੇਟ ਨੂੰ ਗਲੋਬਲ ਸਟੋਰ (ਜਾਂ ਟੌਪ-ਲੈਵਲ context) ਵਿੱਚ ਰੱਖਣਾ ਸੁਚੱਜਾ ਲੱਗ ਸਕਦਾ ਹੈ: ਹਰ ਕੋਈ ਇਸਨੂੰ ਐਕਸੈਸ ਕਰ ਸਕਦਾ ਹੈ ਅਤੇ ਤੁਸੀਂ prop drilling ਤੋਂ ਬਚ ਜਾਂਦੇ ਹੋ। ਪਰ ਟਰੇਡ‑ਆਫ਼ ਹੈ ਅਣਚਾਹੀ coupling—ਅਚਾਨਕ ਗੈਰ-ਸੰਬੰਧਿਤ ਸਕ੍ਰੀਨ ਉਹੀ ਵੈਲਯੂ ਤੇ ਨਿਰਭਰ ਕਰ ਲੈਂਦੇ ਹਨ, ਅਤੇ ਛੋਟੇ ਬਦਲਾਅ ਸਾਰੇ ਐਪ 'ਤੇ ਅਸਰ ਕਰ ਸਕਦੇ ਹਨ।
ਗਲੋਬਲ ਸਟੇਟ ਉਹਨਾਂ ਚੀਜ਼ਾਂ ਲਈ ਵਧੀਆ ਹੈ ਜੋ ਵਾਕਈ ਸਾਰਾ ਐਪ 'ਤੇ ਫੈਲੀਆਂ ਹੋਈਆਂ ਹਨ, ਜਿਵੇਂ ਮੌਜੂਦਾ ਯੂਜ਼ਰ ਸੈਸ਼ਨ, ਐਪ-ਵਾਇਡ ਫੀਚਰ ਫਲੈਗ, ਜਾਂ ਇੱਕ ਸਾਂਝਾ ਨੋਟੀਫਿਕੇਸ਼ਨ ਕਿਊ।
ਆਮ ਪੈਟਰਨ ਇਹ ਹੈ ਕਿ ਸਟੇਟ ਨੂੰ ਲੋਕਲ ਤੋਂ ਸ਼ੁਰੂ ਕਰੋ ਅਤੇ ਜਦੋਂ ਦੋ ਸਬਲਿੰਗ ਭਾਗਾਂ ਨੂੰ ਸਾਂਝੀ ਜੋੜੋ ਭਿੱਖੋ ਤਾਂ ਹੀ ਨਜ਼ਦੀਕੀ ਕੰਮਨ ਪੇਰੇੰਟ ਵੱਲ lift ਕਰੋ।
ਜੇ ਸਿਰਫ਼ ਇੱਕ ਕੰਪੋਨੇਟ ਨੂੰ ਸਟੇਟ ਦੀ ਲੋੜ ਹੈ, ਤਾਂ ਉਸੇ ਵਿੱਚ ਰੱਖੋ। ਜੇ ਕਈ ਕੰਪੋਨੇਟਸ ਨੂੰ ਲੋੜ ਹੈ, ਉਸ ਛੋਟੇ shared owner ਨੂੰ lift ਕਰੋ। ਜੇ ਬਹੁਤ ਸਾਰੇ ਦੂਰਲੇ ਖੇਤਰਾਂ ਨੂੰ ਲੋੜ ਹੈ, ਫਿਰ ਗਲੋਬਲ ਬਾਰੇ ਸੋਚੋ।
ਜਿਤਨਾ ਸੰਭਵ ਹੋਵੇ ਸਟੇਟ ਨੂੰ ਉਸ ਥਾਂ ਦੇ ਕੋਲ ਰੱਖੋ ਜਿੱਥੇ ਇਹ ਵਰਤੀ ਜਾਂਦੀ ہے।
ਇਸ ਨਾਲ ਕੰਪੋਨੇਟਸ ਸਮਝਣ ਵਿਚ آسان ਰਹਿੰਦੇ ਹਨ, ਅਣਚਾਹੀ dependencies ਘੱਟ ਹੁੰਦੀਆਂ ਹਨ, ਅਤੇ ਭਵਿੱਖ ਵਿੱਚ ਰੀਫੈਕਟਰ ਕਰਨਾ ਘੱਟ ਡਰਾਉਣਾ ਹੁੰਦਾ ਹੈ ਕਿਉਂਕਿ ਘੱਟ ਹਿੱਸੇ ਹੀ ਇੱਕੋ ਡੇਟਾ ਨੂੰ ਮਿਊਟੇਟ ਕਰ ਸਕਣਗੇ।
ਫਰੰਟਏਂਡ ਐਪ "ਸਿੰਗਲ-ਥਰੇਡ" ਜਿਹਾ ਮਹਿਸੂਸ ਕਰਾਉਂਦੇ ਹਨ, ਪਰ ਯੂਜ਼ਰ ਇਨਪੁਟ, ਟਾਈਮਰ, ਐਨੀਮੇਸ਼ਨ, ਅਤੇ ਨੈੱਟਵਰਕ ਰਿਕਵੇਸਟ ਸਭ ਅਲੱਗ-ਅਲੱਗ ਚੱਲਦੇ ਹਨ। ਇਸਦਾ ਮਤਲਬ ਹੈ ਕਿ ਇਕੋ ਸਮੇਂ ਕਈ ਅਪਡੇਟ ਫਲਾਈਟ ਵਿੱਚ ਹੋ ਸਕਦੇ ਹਨ—ਅਤੇ ਉਹ ਜਰੂਰੀ ਨਹੀਂ ਕਿ ਤੁਸੀਂ ਜਿਹੜੀ ਕ੍ਰਮ ਵਿੱਚ ਸ਼ੁਰੂ ਕੀਤਾ ਓਸੇ ਕ੍ਰਮ ਵਿੱਚ ਖਤਮ ਹੋਣ।
ਇੱਕ ਆਮ ਟਕਰਾਅ: UI ਦੇ ਦੋ ਹਿੱਸੇ ਇਕੋ ਸਟੇਟ ਨੂੰ ਅਪਡੇਟ ਕਰਦੇ ਹਨ।
query ਅਪਡੇਟ ਕਰਦਾ ਹੈ।query (ਜਾਂ ਉਹੀ results ਲਿਸਟ) ਅਪਡੇਟ ਕਰਦਾ ਹੈ।ਅਲੱਗ-ਅਲੱਗ, ਹਰ ਅਪਡੇਟ ਸਹੀ ਹੈ। ਇਕੱਠੇ, ਉਹ ਟਾਈਮਿੰਗ ਦੇ ਅਨੁਸਾਰ ਇਕ ਦੂਜੇ ਨੂੰ ਓਵਰਰਾਈਟ ਕਰ ਸਕਦੇ ਹਨ। ਹੋਰ ਬੁਰਾ ਇਹ ਹੈ ਕਿ ਤੁਸੀਂ ਪਹਿਲਾਂ ਵਾਲੀ ਕੁਇਰੀ ਦੇ ਨਤੀਜੇ ਦਿਖਾ ਸਕਦੇ ਹੋ ਜਦਕਿ UI ਨਵੇਂ ਫਿਲਟਰ ਦਿਖਾ ਰਿਹਾ ਹੋਵੇ।
ਰੇਸ ਕਨਡੀਸ਼ਨ ਉਸ ਵੇਲੇ ਆਉਂਦੇ ਹਨ ਜਦੋਂ ਤੁਸੀਂ ਰਿਕਵੇਸਟ A ਭੇਜੋ, ਫਿਰ ਜਲਦੀ ਰਿਕਵੇਸਟ B ਭੇਜੋ—ਪਰ ਰਿਕਵੇਸਟ A ਆਖਿਰ ਵਿੱਚ ਬਾਅਦ ਵਿੱਚ ਆ ਜਾਵੇ।
ਉਦਾਹਰਨ: ਯੂਜ਼ਰ "c", "ca", "cat" ਟਾਈਪ ਕਰਦਾ ਹੈ। ਜੇ "c" ਰਿਕਵੇਸਟ ਧੀਮਾ ਹੈ ਅਤੇ "cat" ਰਿਕਵੇਸਟ ਤੇਜ਼ ਹੈ, ਤਾਂ UI ਛੋਟੀ ਦੇਰ ਲਈ "cat" ਨਤੀਜੇ ਦਿਖਾ ਸਕਦੀ ਹੈ ਅਤੇ ਫਿਰ ਪੁਰਾਣੀ "c" ਨਤੀਜੇ ਆਕੇ ਓਵਰਰਾਈਟ ਕਰ ਦੇਂਦੀ ਹੈ।
ਬੱਗ ਸੁਕੇਤਪੂਰਨ ਹੁੰਦੀ ਹੈ ਕਿਉਂਕਿ ਸਭ ਕੁਝ "ਕਾਮ" ਕਰ ਰਿਹਾ ਸੀ—ਸਿਰਫ਼ ਗਲਤ ਕ੍ਰਮ ਵਿੱਚ।
ਆਮ ਤੌਰ 'ਤੇ ਤੁਸੀਂ ਇਨ੍ਹਾਂ ਵਿੱਚੋਂ ਇੱਕ ਰਣਨੀਤੀ ਚਾਹੁੰਦੇ ਹੋ:
AbortController ਵਰਤ ਕੇ)।ਇੱਕ ਸਧਾਰਨ request ID ਢਾਂਚਾ:
let latestRequestId = 0;
async function fetchResults(query) {
const requestId = ++latestRequestId;
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`);
const data = await res.json();
if (requestId !== latestRequestId) return; // stale response
setResults(data);
}
Optimistic updates UI ਨੂੰ ਤੁਰੰਤ ਮਹਿਸੂਸ ਕਰਵਾਉਂਦੀਆਂ ਹਨ: ਤੁਸੀਂ ਸਕਰੀਨ ਨੂੰ ਸਰਵਰ ਤੋਂ ਪੁਸ਼ਟੀ ਮਿਲਣ ਤੋਂ ਪਹਿਲਾਂ ਅਪਡੇਟ ਕਰ ਦਿੰਦੇ ਹੋ। ਪਰ concurrency ਅਸਮਾਨਥਾਵਾਂ ਨੂੰ ਤੋੜ ਸਕਦਾ ਹੈ:
Optimism ਨੂੰ ਸੁਰੱਖਿਅਤ ਰੱਖਣ ਲਈ, ਤੁਹਾਨੂੰ ਆਮ ਤੌਰ 'ਤੇ ਸਪੱਸ਼ਟ reconciliation rule ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ: pending action ਨੂੰ ਟਰੈਕ ਕਰੋ, ਸਰਵਰ ਰਿਸਪਾਂਸਾਂ ਨੂੰ క੍ਰਮ ਵਿੱਚ ਲਾਗੂ ਕਰੋ, ਅਤੇ ਜੇ rollback ਕਰਨਾ ਪਵੇ ਤਾਂ ਇੱਕ ਪਤਾ ਚੱਲਣ ਵਾਲੇ checkpoint 'ਤੇ rollback ਕਰੋ (ਨਾ ਕਿ "ਜੋ UI ਹੁਣ ਦਿੱਸ ਰਿਹਾ" ਤੇ)।
ਸਟੇਟ ਅਪਡੇਟ "ਮੁਫ਼ਤ" ਨਹੀਂ ਹੁੰਦੇ। ਜਦੋਂ ਸਟੇਟ ਬਦਲਦੀ ਹੈ, ਐਪ ਨੂੰ ਇਹ ਦੱਸਣਾ ਪੈਂਦਾ ਹੈ ਕਿ ਸਕਰੀਨ ਦੇ ਕਿਹੜੇ ਹਿੱਸੇ ਪ੍ਰਭਾਵਿਤ ਹੋ ਸਕਦੇ ਹਨ ਅਤੇ ਫਿਰ ਉਹ ਕੰਮ ਕਰਨਾ ਪੈਂਦਾ ਹੈ ਜੋ ਨਵੇਂ ਹਾਲਤ ਨੂੰ ਦਰਸਾਉਣ ਲਈ ਲੋੜੀਂਦਾ ਹੈ: ਮੁਲਾਂਕਣ ਰੀਕੈਲਕੁਲੇਟ ਕਰਨਾ, UI ਨੂੰ ਰੀ-ਰੈਂਡਰ ਕਰਨਾ, ਫਾਰਮੈਟਿੰਗ ਲਾਜਿਕ ਨੂੰ ਮੁੜ ਚਲਾਉਣਾ, ਅਤੇ ਕਦੇ-ਕਦੇ ਫੇਚ ਜਾਂ ਵੈਰੀਫਿਕੇਸ਼ਨ ਕਰਨਾ। ਜੇ ਉਹ ਚੇਨ ਰੀਏਕਸ਼ਨ ਜ਼ਰੂਰੀ ਤੋਂ ਵੱਧ ਵੱਡੀ ਹੈ, ਤਾਂ ਯੂਜ਼ਰ ਨੂੰ ਲੱਗਦਾ ਹੈ ਕਿ ਐਪ ਸੁਸਤ ਹੈ, ਜੈਂਕ ਆ ਰਿਹਾ ਹੈ, ਜਾਂ ਬਟਨ ਨੂੰ ਦਬਾਉਣ ਤੇ "ਸੋਚ" ਕਰਨ ਵਰਗਾ ਮਹਿਸੂਸ ਹੁੰਦਾ ਹੈ।
ਇੱਕ ਸਿੰਗਲ ਟੌਗਲ ਬੇਲਕੁਲ ਬਹੁਤ ਸਾਰੇ ਕੰਮ trigger ਕਰ ਸਕਦਾ ਹੈ:
ਨਤੀਜਾ ਨਾਂ ਸਿਰਫ਼ ਤਕਨੀਕੀ ਹੁੰਦਾ ਹੈ—ਇਹ ਅਨੁਭਵ ਵੀ ਪ੍ਰਭਾਵਿਤ ਕਰਦਾ ਹੈ: ਟਾਈਪਿੰਗ ਵਿੱਚ ਦੇਰ, ਐਨੀਮੇਸ਼ਨ ਰੁਕਣਾ, ਅਤੇ ਇੰਟਰਫੇਸ ਉਹ "ਸਨੈਪੀ" ਗੁਣ ਗੁਆ ਦਿੰਦਾ ਹੈ ਜੋ ਲੋਕ polished ਉਤਪਾਦ ਨਾਲ ਜੋੜਦੇ ਹਨ।
ਇੱਕ ਆਮ ਕਾਰਣ ਉਹ ਸਟੇਟ ਹੈ ਜੋ ਬਹੁਤ ਵਿਆਪਕ ਹੈ: ਇੱਕ "ਵੱਡਾ ਬੱਕੇਟ" ਓਬਜੈਕਟ ਜਿਸ ਵਿੱਚ ਬੇਹੱਦ ਸਾਰੀਆਂ ਬੇਰਲਾਇਟ ਜਾਣਕਾਰੀ ਹੁੰਦੀ ਹੈ। ਕਿਸੇ ਵੀ ਫੀਲਡ ਨੂੰ ਅਪਡੇਟ ਕਰਨ ਨਾਲ ਪੂਰਾ ਬੱਕੇਟ ਨਵਾਂ ਦਿੱਸਦਾ ਹੈ, ਇਸ ਲਈ ਜ਼ਿਆਦਾ UI ਜਾਗਦਾ ਹੈ ਜਿੱਤਿਆ ਲੋੜੀਦਾ ਨਹੀਂ।
ਦੂਜਾ ਫਸ computed values ਨੂੰ ਸਟੇਟ ਵਿੱਚ ਰੱਖਣਾ ਅਤੇ ਉਨ੍ਹਾਂ ਨੂੰ ਹੱਥੀ ਨਾਲ ਅਪਡੇਟ ਕਰਨਾ ਹੈ। ਇਸ ਨਾਲ ਅਕਸਰ ਵਾਧੂ ਅਪਡੇਟ ਹੁੰਦੇ ਹਨ (ਅਤੇ ਵਾਧੂ UI ਕੰਮ) ਸਿਰਫ ਇਹ ਯਕੀਨੀ ਬਣਾਉਣ ਲਈ ਕਿ ਸਭ ਕੁਝ ਮਿਲਦਾ ਜੁਲਦਾ ਰਹੇ।
ਸਟੇਟ ਨੂੰ ਛੋਟੇ ਸਲਾਈਸਾਂ ਵਿੱਚ ਵੰਡੋ। ਅਣਸੰਬੰਧਤ ਚਿੰਤਾਵਾਂ ਨੂੰ ਅਲੱਗ ਰੱਖੋ ਤਾਂ ਕਿ ਖੋਜ ਇਨਪੁਟ ਅਪਡੇਟ ਹੋਣ 'ਤੇ ਪੂਰੇ ਪੇਜ਼ ਦੇ ਰੇਫਰੇਸ਼ ਨਾ ਹੋਣ।
ਡੇਟਾ ਨੂੰ ਨਾਰਮਲਾਈਜ਼ ਕਰੋ। ਇਕੋ ਆਈਟਮ ਨੂੰ ਕਈ ਥਾਂ ਸਟੋਰ ਕਰਨ ਦੀ ਬਜਾਏ ਇੱਕ ਵਾਰ ਸਟੋਰ ਕਰੋ ਅਤੇ ਹਵਾਲੇ ਰੱਖੋ। ਇਹ ਦੁਹਰਾਏ ਅਪਡੇਟ ਘਟਾਉਂਦਾ ਹੈ ਅਤੇ "ਚੇਂਜ ਸਟਾਰਮ" ਰੋਕਦਾ ਹੈ ਜਿੱਥੇ ਇੱਕ ਸੋਧ ਕਈ ਨਕਲਾਂ ਨੂੰ ਮੁੜ-ਲਿਖਣਾ ਪਿਆ ਕਰਦਾ ਹੈ।
Derived values ਨੂੰ ਮੈਮੋਇਜ਼ ਕਰੋ। ਜੇ ਕੋਈ ਵੈਲਯੂ ਹੋਰ ਸਟੇਟ ਤੋਂ ਗਣਨਾ ਕੀਤੀ ਜਾ ਸਕਦੀ ਹੈ (ਜਿਵੇਂ filtered results), ਉਸ ਗਣਨਾ ਨੂੰ ਕੈਸ਼ ਕਰੋ ਤਾਂ ਕਿ ਇਹ ਸਿਰਫ਼ ਉਸ ਵੇਲੇ ਮੁੜ-ਕੈਲਕੁਲੇਟ ਹੋਵੇ ਜਦੋਂ ਇਨਪੁੱਟਸ ਅਸਲ ਵਿੱਚ ਬਦਲਣ।
ਚੰਗੀ ਪ੍ਰਦਰਸ਼ਨ-ਮਨੁੱਖਤਾ ਵਾਲੀ ਸਟੇਟ ਮੈਨੇਜਮੈਂਟ ਜ਼ਰਦਾਦ ਤਕਰੀਬਨ containment ਬਾਰੇ ਹੈ: ਅਪਡੇਟਸ ਸਭ ਤੋਂ ਛੋਟੇ ਸੰਭਾਵਿਤ ਖੇਤਰ ਨੂੰ ਪ੍ਰਭਾਵਿਤ ਕਰਨੇ ਚਾਹੀਦੇ ਹਨ, ਅਤੇ ਮਹਿੰਗਾ ਕੰਮ ਸਿਰਫ਼ ਜਦੋਂ ਵਾਕਈ ਲੋੜ ਹੋਵੇ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ। ਜਦ ਇਹ ਸਚ ਹੁੰਦਾ ਹੈ, ਤਾਂ ਉਪਭੋਗੀ ਫਰੇਮਵਰਕ ਨੂੰ ਨਾ ਜਾਪਣ ਦਿੰਦੇ ਅਤੇ ਇੰਟਰਫੇਸ 'ਤੇ ਭਰੋਸਾ ਕਰਦੇ ਹਨ।
ਸਟੇਟ ਬੱਗ ਅਕਸਰ ਨਿੱਜੀ ਮਹਿਸੂਸ ਹੁੰਦੇ ਹਨ: UI "ਗਲਤ" ਹੈ, ਪਰ ਤੁਸੀਂ ਸਭ ਤੋਂ ਸਧਾਰਨ ਸਵਾਲ ਦਾ ਜਵਾਬ ਨਹੀਂ ਦੇ ਸਕਦੇ—ਇਸ ਵੈਲਯੂ ਨੂੰ ਕਿਸਨੇ ਅਤੇ ਕਦੋਂ ਬਦਲਿਆ ਸੀ? ਜੇ ਕੋਈ ਨੰਬਰ ਫਲਿੱਪ ਹੋਏ, ਬੈਨਰ ਦੂਰ ਹੋ ਗਿਆ, ਜਾਂ ਬਟਨ ਆਪਣਾ ਆਪ ਡਿਸੇਬਲ ਹੋ ਗਿਆ, ਤੁਹਾਨੂੰ ਸੂਚੀ ਨਹੀਂ ਬਲਕਿ ਟਾਈਮਲਾਈਨ ਚਾਹੀਦੀ ਹੈ।
ਸਪੱਸ਼ਟ ਅਪਡੇਟ ਫਲੋ ਸਭ ਤੋਂ ਤੇਜ਼ ਰਸਤਾ ਸਪਸ਼ਟਤਾ ਵੱਲ ਹੈ। ਚਾਹੇ ਤੁਸੀਂ reducers, events, ਜਾਂ ਇੱਕ store ਵਰਤੋ, ਇਕ ਪੈਟਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰੋ ਜਿਸ ਵਿੱਚ:
setShippingMethod('express'), ਨਾ ਕਿ updateStuff)ਸਪੱਸ਼ਟ action ਲੌਗਿੰਗ ਡੀਬੱਗਿੰਗ ਨੂੰ "ਸਕਰੀਨ ਨੂੰ ਤੱਕਣਾ" ਤੋਂ ਬਦਲ ਕੇ "ਰਸੀਦ ਨੂੰ ਫਾਲੋ ਕਰੋ" ਵਿੱਚ ਬਦਲ ਦਿੰਦੀ ਹੈ। ਸਧਾਰਨ console logs (action name + ਕੁੰਜੀ ਖੇਤਰ) ਵੀ ਲੱਭਣ ਵਿੱਚ ਕਾਫ਼ੀ ਮਦਦਗਾਰ ਹੁੰਦੇ ਹਨ।
ਹਰ ਰੀ-ਰੈਂਡਰ ਨੂੰ ਟੈਸਟ ਕਰਨ ਦੀ ਕੋਸ਼ਿਸ਼ ਨਾ ਕਰੋ। ਬਦਲੇ ਵਿੱਚ, ਉਹ ਹਿੱਸੇ ਟੈਸਟ ਕਰੋ ਜੋ pure logic ਵਾਂਗ ਵਰਤਦੇ ਹਨ:
ਇਹ ਮਿਲਾ-ਜੁਲੀ ਪਹੁੰਚ "ਗਣਿਤੀ ਬੱਗ" ਅਤੇ ਅਸਲ-ਦੁਨੀਆ ਵਾਇਰਿੰਗ ਮੁੱਦੇ ਦੋਹਾਂ ਫੜ ਲੈਂਦੀ ਹੈ।
ਐਸਿੰਕ ਸਮੱਸਿਆਵਾਂ ਗੈਪ ਵਿੱਚ ਛੁਪਦੀਆਂ ਹਨ। ਟਾਈਮਲਾਈਨ ਨੂੰ ਦਿਖਾਉਣ ਵਾਲਾ ਘੱਟੋ-ਘੱਟ ਮੈਟਾਡੇਟਾ ਜੋੜੋ:
ਫਿਰ ਜਦੋਂ ਇੱਕ ਦੇਰ ਨਾਲ ਆਈ ਰਿਸਪਾਂਸ ਨਵੇਂ ਨੂੰ ਓਵਰਰਾਈਟ ਕਰ ਦੇਵੇ, ਤੁਸੀਂ ਤੁਰੰਤ ਇਹ ਸਾਬਤ ਕਰ ਸਕਦੇ ਹੋ—ਅਤੇ ਵਿਸ਼ਵਾਸ ਨਾਲ ਇਸਨੂੰ ਠੀਕ ਕਰ ਸਕਦੇ ਹੋ।
ਸਟੇਟ ਟੂਲ ਚੁਣਨਾ ਅਸਾਨ ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਇਸਨੂੰ ਡਿਜ਼ਾਇਨ ਫੈਸਲਿਆਂ ਦੇ ਨਤੀਜੇ ਵਜੋਂ ਦੇਖਦੇ ਹੋ, ਸ਼ੁਰੂਆਤ ਵਜੋਂ ਨਹੀਂ। ਲਾਇਬ੍ਰੇਰੀਆਂ ਦੀ ਤੁਲਨਾ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ, ਆਪਣੇ سਟੇਟ ਸীਮਾਵਾਂ ਦਾ ਨਕਸ਼ਾ ਬਣਾਓ: ਕੀ ਪਿਉਰੇ ਕੰਪੋਨੇਟ ਲਈ ਲੋਕਲ ਹੈ, ਕੀ ਸਾਂਝਾ ਹੋਣਾ ਹੈ, ਅਤੇ ਕੀ asal 'server data' ਹੈ ਜੋ ਤੁਹਾਨੂੰ ਫੈਚ ਅਤੇ ਸਿੰਕ ਕਰਨਾ ਹੈ।
ਇਕ ਪ੍ਰਾਇਗਮੈਟਿਕ ਤਰੀਕਾ ਇਹ ਹੈ ਕਿ ਕੁਝ ਬੰਧਨਾਂ ਤੇ ਨਜ਼ਰ ਕਰੋ:
ਜੇ ਤੁਸੀਂ ਸ਼ੁਰੂ ਤੋਂ ਹੀ "ਅਸੀਂ X ਹਰ ਜਗ੍ਹਾ ਵਰਤਦੇ ਹਾਂ" ਨਾਲ ਸ਼ੁਰੂ ਕਰੋਗੇ, ਤਾਂ ਤੁਸੀਂ ਗਲਤ ਚੀਜ਼ਾਂ ਗਲਤ ਥਾਂ ਤੇ ਰੱਖੋਗੇ। "ਮਾਲਕੀ" ਤੋਂ ਸ਼ੁਰੂ ਕਰੋ: ਕੌਣ ਅਪਡੇਟ ਕਰਦਾ ਹੈ, ਕੌਣ ਪੜ੍ਹਦਾ ਹੈ, ਅਤੇ ਬਦਲਣ 'ਤੇ ਕੀ ਹੋਣਾ ਚਾਹੀਦਾ ਹੈ।
ਕਈ ਐਪ ਇੱਕ server-state ਲਾਇਬ੍ਰੇਰੀ API ਡੇਟਾ ਲਈ ਅਤੇ ਇੱਕ ਛੋਟੀ UI-state ਹੱਲ client-only ਮਾਮਲਿਆਂ ਲਈ (ਜਿਵੇਂ ਮੋਡਲ, ਫਿਲਟਰ, ਜਾਂ ਡ੍ਰਾਫਟ ਫਾਰਮ) ਨਾਲ ਚੰਗਾ ਕਰਦੇ ਹਨ। ਮਕਸਦ ਸਪਸ਼ਟਤਾ ਹੈ: ਹਰ ਤਰ੍ਹਾਂ ਦੀ ਸਟੇਟ ਉਸ ਥਾਂ ਰੱਖੋ ਜਿੱਥੇ ਉਹ ਫ਼ੈਸਲਾ ਕਰਨ ਲਈ ਸਭ ਤੋਂ ਆਸਾਨ ਹੋ।
ਜੇ ਤੁਸੀਂ ਸਟੇਟ ਬਾਊਂਡਰੀਆਂ ਅਤੇ ਐਸਿੰਕ ਫਲੋਜ਼ 'ਤੇ ਇਟਰੇਟ ਕਰ ਰਹੇ ਹੋ, Koder.ai "ਕੋਸ਼ਿਸ਼ ਕਰੋ, ਨਿਰੀਖਣ ਕਰੋ, ਸੁਧਾਰੋ" ਲੂਪ ਨੂੰ ਤੇਜ਼ ਕਰ ਸਕਦਾ ਹੈ। ਕਿਉਂਕਿ ਇਹ chat ਨਾਲ ਏਜੈਂਟ-ਅਧਾਰਤ ਵਰਕਫਲੋ ਤੋਂ React ਫਰੰਟੇਂਡ (ਅਤੇ Go + PostgreSQL ਬੈਕਐਂਡ) ਜੇਨੇਰੇਟ ਕਰਦਾ ਹੈ, ਤੁਸੀਂ ਲੋਕਲ ਵਿਰੁੱਧ ਗਲੋਬਲ, ਸਰਵਰ ਕੈਸ਼ ਵਿਰੁੱਧ UI ਡ੍ਰਾਫਟ ਵਰਗੀਆਂ ਮਾਲਕੀ ਮਾਡਲਾਂ ਤੇਜ਼ੀ ਨਾਲ ਪ੍ਰੋਟੋਟਾਈਪ ਕਰ ਸਕਦੇ ਹੋ, ਅਤੇ ਫਿਰ ਉਹ ਵਰਜਨ ਰੱਖ ਸਕਦੇ ਹੋ ਜੋ ਭਰੋਸੇਯੋਗ ਰਹਿੰਦਾ ਹੈ।
ਦੋ ਪ੍ਰਾਇਗਮੈਟਿਕ ਫੀਚਰ ਜਦੋਂ ਤਜਰਬਾ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੋਵੇ ਤਾਂ ਮਦਦਗਾਰ ਹੁੰਦੇ ਹਨ: Planning Mode (ਸਟੇਟ ਮਾਡਲ ਬਣਾਉਣ ਲਈ ਕੰਮ ਕਰਨਾ) ਅਤੇ snapshots + rollback (ਇਹ ਇਕ ਸੁਰੱਖਿਅਤ ਬੇਸਲਾਈਨ ਰੱਖ ਕੇ reducers, caches, selectors ਵਾਂਗ refactors ਟੈਸਟ ਕਰਨ ਲਈ)।
ਜਦੋਂ ਕੋਈ ਕੰਪੋਨੇਟ "ਰਹੱਸਮਈ" ਮਹਿਸੂਸ ਹੋਵੇ, ਤਾਂ ਸਟੇਟ ਨੂੰ ਇੱਕ ਡਿਜ਼ਾਇਨ ਸਮੱਸਿਆ ਵਾਂਗ ਦੇਖੋ: ਫੈਸਲਾ ਕਰੋ ਕਿ ਕੌਣ ਇਸ ਦੀ ਮਾਲਕੀ ਹੈ, ਇਹ ਕੀ ਦਰਸਾਉਂਦਾ ਹੈ, ਅਤੇ ਇਹ ਕਿਵੇਂ ਬਦਲਦਾ ਹੈ। ਇਹ ਚੈੱਕਲਿਸਟ ਵਰਤੋ।
ਪੋਛੋ: ਐਪ ਦਾ ਕਿਹੜਾ ਹਿੱਸਾ ਇਸ ਡੇਟਾ ਲਈ ਉੱਤਰਦਾਇਤ ਹੈ? ਸਟੇਟ ਨੂੰ ਉਸ ਥਾਂ ਦੇ ਨੇੜੇ ਰੱਖੋ ਜਿੱਥੇ ਇਹ ਵਰਤੀ ਜਾਂਦੀ ਹੈ, ਅਤੇ ਸਿਰਫ਼ ਜਦੋਂ ਬਹੁਤ ਸਾਰੇ ਹਿੱਸੇ ਵਾਕਈ ਸਹਯੋਗੀ ਹੋਣ ਤਾਂ ਹੀ ਇਸਨੂੰ lift ਕਰੋ।
ਜੇ ਤੁਸੀਂ ਕਿਸੇ ਚੀਜ਼ ਨੂੰ ਹੋਰ ਸਟੇਟ ਤੋਂ ਗਣਨਾ ਕਰ ਸਕਦੇ ਹੋ, ਤਾਂ ਉਸਨੂੰ ਸਟੋਰ ਨਾ ਕਰੋ।
items, filterText).visibleItems) ਨੂੰ ਰੇਂਡਰ ਸਮੇਂ ਜਾਂ memoization ਰਾਹੀਂ ਗਣਨਾ ਕਰੋ।ਐਸਿੰਕ ਕੰਮ ਉਸ ਵੇਲੇ ਸਪੱਸ਼ਟ ਹੁੰਦੇ ਹਨ ਜਦੋਂ ਤੁਸੀਂ ਉਹਨਾਂ ਨੂੰ ਸੀਧਾ ਮਾਡਲ ਕਰੋ:
status: 'idle' | 'loading' | 'success' | 'error', ਨਾਲ data ਅਤੇ error।isLoading, isFetching, isSaving, hasLoaded, …) ਬਜਾਏ ਇੱਕ ਸਿੰਗਲ status ਵਰਤੋ।ਕੋਸ਼ਿਸ਼ ਕਰੋ ਕਿ ਘੱਟ "ਇਹ ਕਿਵੇਂ ਇਸ ਹਾਲਤ ਵਿੱਚ ਆ ਗਿਆ?" ਵਾਲੇ ਬੱਗ ਰਹਿਣ, ਬਦਲਾਅ ਜੋ ਪੰਜ ਫ਼ਾਇਲਾਂ ਛੇੜਨ ਦੀ ਲੋੜ ਨਾ ਪਏ, ਅਤੇ ਇੱਕ ਮਾਨਸਿਕ ਮਾਡਲ ਜਿੱਥੇ ਤੁਸੀਂ ਇੱਕ ਥਾਂ ਉੱਪਰ ਇਸ਼ਾਰਾ ਕਰ ਸਕੋ ਅਤੇ ਕਹਿ ਸਕੋ: ਇਥੇ ਸੱਚ ਰਹਿੰਦਾ ਹੈ।