ਤੁਹਾਡੇ ਯੂਜ਼ਰ ਦਾ ਬ੍ਰਾਊਜ਼ਰ ਟੈਬ ਤੀਹ ਮਿੰਟਾਂ ਬਾਅਦ ਫ੍ਰੀਜ਼ ਹੋ ਜਾਂਦਾ ਹੈ। UI ਅਟਕਣ ਲੱਗਦੀ ਹੈ। ਫਿਰ ਬ੍ਰਾਊਜ਼ਰ 'out-of-memory' ਐਰਰ ਨਾਲ ਕ੍ਰੈਸ਼ ਹੋ ਜਾਂਦਾ ਹੈ।

ਤੁਸੀਂ ਕੰਪੋਨੈਂਟ ਕੋਡ ਦੀ ਲਾਈਨ-ਦਰ-ਲਾਈਨ ਸਮੀਖਿਆ ਕਰਦੇ ਹੋ ਅਤੇ ਕੁਝ ਵੀ ਗਲਤ ਨਹੀਂ ਦੇਖਦੇ। React ਵਿੱਚ ਮੈਮੋਰੀ ਲੀਕਸ (memory leaks) ਦਾ ਇਹ ਸਭ ਤੋਂ ਪਰੇਸ਼ਾਨ ਕਰਨ ਵਾਲਾ ਹਿੱਸਾ ਹੈ। ਇਹ ਬੱਗ ਤੁਹਾਡੇ JSX ਸਿੰਟੈਕਸ ਜਾਂ ਤੁਹਾਡੇ hook ਲੌਜਿਕ ਵਿੱਚ ਨਹੀਂ ਹੁੰਦਾ। ਇਹ ਤੁਹਾਡੇ ਕੰਪੋਨੈਂਟ ਅਤੇ ਬ੍ਰਾਊਜ਼ਰ ਦੇ garbage collector ਦੇ ਵਿਚਕਾਰਲੇ ਅੰਤਰ ਵਿੱਚ ਹੁੰਦਾ ਹੈ। ਇੱਕ ਵਾਧੂ event listener ਜਾਂ ਇੱਕ ਲੰਬੇ ਸਮੇਂ ਤੱਕ ਚੱਲਣ ਵਾਲਾ closure collector ਨੂੰ ਮੈਮੋਰੀ ਵਾਪਸ ਲੈਣ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਸੀਂ ਇੱਕ ਕੰਪੋਨੈਂਟ ਨੂੰ unmount ਕਰਦੇ ਹੋ, ਪਰ ਇੱਕ ਇਕੱਲਾ ਰਹਿ ਗਿਆ reference ਪੂਰੇ tree ਨੂੰ heap ਵਿੱਚ ਜਿਉਂਦਾ ਰੱਖਦਾ ਹੈ। ਤੁਸੀਂ ਸਿਰਫ਼ ਕੋਡ ਪੜ੍ਹ ਕੇ ਇਹਨਾਂ ਲੀਕਸ ਨੂੰ ਨਹੀਂ ਲੱਭ ਸਕਦੇ। ਸਮੱਸਿਆ ਸਤ੍ਹਾ ਦੇ ਹੇਠਾਂ ਲੁਕੀ ਰਹਿੰਦੀ ਹੈ, ਜੋ ਅੱਖਾਂ ਨੂੰ ਦਿਖਾਈ ਨਹੀਂ ਦਿੰਦੀ ਅਤੇ unit tests ਵਿੱਚ ਵੀ ਸ਼ਾਂਤ ਰਹਿੰਦੀ ਹੈ।

ਲੀਕਸ ਸਾਹਮਣੇ ਹੋ ਕੇ ਵੀ ਕਿਉਂ ਲੁਕੇ ਰਹਿੰਦੇ ਹਨ

V8 ਵਰਗੇ JavaScript engines ਮੈਮੋਰੀ ਨੂੰ ਆਪਣੇ ਆਪ ਪ੍ਰਬੰਧਿਤ ਕਰਦੇ ਹਨ। ਜਦੋਂ root ਤੋਂ ਕਿਸੇ object ਤੱਕ ਕੋਈ reference path ਨਹੀਂ ਬਚਦਾ, ਤਾਂ engine ਉਸ object ਨੂੰ garbage ਵਜੋਂ ਚਿੰਨ੍ਹਿਤ ਕਰ ਦਿੰਦਾ ਹੈ ਅਤੇ ਉਹ ਜਗ੍ਹਾ ਵਾਪਸ ਲੈ ਲੈਂਦਾ ਹੈ। ਇਹ ਪ੍ਰਕਿਰਿਆ ਉਦੋਂ ਤੱਕ ਵਧੀਆ ਕੰਮ ਕਰਦੀ ਹੈ ਜਦੋਂ ਤੱਕ ਕੋਈ ਲੁਕਿਆ ਹੋਇਆ reference ਤੁਹਾਡੇ ਇਰਾਦੇ ਨਾਲੋਂ ਜ਼ਿਆਦਾ ਸਮੇਂ ਤੱਕ ਜਿਉਂਦਾ ਰਹਿੰਦਾ ਹੈ।

React ਵਿੱਚ, ਖ਼ਤਰਾ ਅਕਸਰ components ਅਤੇ DOM ਦੇ ਵਿਚਕਾਰਲੇ ਸਰਹੱਦ 'ਤੇ ਦਿਖਾਈ ਦਿੰਦਾ ਹੈ। ਤੁਸੀਂ ਕਿਸੇ modal ਦੇ ਅੰਦਰ window ਨੂੰ resize listener ਨਾਲ ਜੋੜ ਸਕਦੇ ਹੋ, ਜਾਂ dashboard widget ਵਿੱਚ WebSocket ਨੂੰ subscribe ਕਰ ਸਕਦੇ ਹੋ। ਜਦੋਂ ਯੂਜ਼ਰ modal ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਕਿਸੇ ਹੋਰ ਪੇਜ 'ਤੇ ਜਾਂਦਾ ਹੈ, ਤਾਂ ਕੰਪੋਨੈਂਟ unmount ਹੋ ਜਾਂਦਾ ਹੈ। ਜੇਕਰ subscription ਬਚੀ ਰਹਿੰਦੀ ਹੈ, ਤਾਂ engine global window object ਤੋਂ ਲੈ ਕੇ ਤੁਹਾਡੇ handler ਤੱਕ, ਅਤੇ ਤੁਹਾਡੇ handler ਤੋਂ ਵਾਪਸ ਕੰਪੋਨੈਂਟ ਦੇ closure ਤੱਕ ਇੱਕ ਵੈਧ (valid) reference ਦੇਖਦਾ ਹੈ। ਕੰਪੋਨੈਂਟ, ਉਸਦੇ props, ਉਸਦੀ state, ਅਤੇ DOM nodes ਦਾ ਪੂਰਾ subtree ਮੈਮੋਰੀ ਵਿੱਚ ਫਸਿਆ ਰਹਿੰਦਾ ਹੈ। ਸੈਂਕੜੇ ਇੰਟਰੈਕਸ਼ਨਾਂ ਦੇ ਨਾਲ, ਇਹ ਫਸੇ ਹੋਏ objects ਇਕੱਠੇ ਹੋ ਜਾਂਦੇ ਹਨ। ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ sawtooth pattern ਵਿੱਚ ਵਧਦੀ ਹੈ ਜੋ ਕਦੇ ਵੀ ਪੂਰੀ ਤਰ੍ਹਾਂ ਹੇਠਾਂ ਨਹੀਂ ਆਉਂਦੀ।

ਐਂਟਰਪ੍ਰਾਈਜ਼ ਡੈਸ਼ਬੋਰਡ ਦੀ ਸਮੱਸਿਆ

ਇਹ ਜ਼ਿਆਦਾਤਰ ਐਂਟਰਪ੍ਰਾਈਜ਼ ਡੈਸ਼ਬੋਰਡਾਂ ਵਿੱਚ ਹੁੰਦਾ ਹੈ ਜਿੱਥੇ ਯੂਜ਼ਰ ਘੰਟਿਆਂ ਬੱਧੀ ਇੱਕ ਹੀ ਪੇਜ 'ਤੇ ਰਹਿੰਦੇ ਹਨ। ਮਾਨੀਟਰਿੰਗ ਪੈਨਲਾਂ, ਐਨਾਲਿਟਿਕਸ ਵਿਊਜ਼, ਜਾਂ ਟਿਕਟਿੰਗ ਸਿਸਟਮਾਂ ਬਾਰੇ ਸੋਚੋ। ਇੱਕ ਯੂਜ਼ਰ ਡਿਟੇਲ modal ਖੋਲ੍ਹਦਾ ਹੈ, ਇੱਕ ਵੱਡੇ dataset ਨੂੰ filter ਕਰਦਾ ਹੈ, ਜਾਂ single-page app ਦੇ ਅੰਦਰ tabs ਬਦਲਦਾ ਹੈ। ਹਰ ਇੱਕ ਵੱਖਰਾ ਇੰਟਰੈਕਸ਼ਨ ਠੀਕ ਲੱਗਦਾ ਹੈ। ਹਾਲਾਂਕਿ, ਸਮੇਂ ਦੇ ਨਾਲ, orphaned nodes ਅਤੇ detached listeners ਇਕੱਠੇ ਹੋ ਜਾਂਦੇ ਹਨ। ਐਪਲੀਕੇਸ਼ਨ ਇਸ ਲਈ ਹੌਲੀ ਨਹੀਂ ਹੁੰਦੀ ਕਿਉਂਕਿ ਕੋਈ ਇੱਕ ਮਹਿੰਗਾ render ਹੋ ਰਿਹਾ ਹੈ, ਸਗੋਂ ਇਸ ਲਈ ਕਿਉਂਕਿ heap ਇੰਨਾ ਵੱਡਾ ਹੋ ਜਾਂਦਾ ਹੈ ਕਿ ਵਾਰ-ਵਾਰ ਅਤੇ ਮਹਿੰਗੇ garbage collection pauses ਸ਼ੁਰੂ ਹੋ ਜਾਂਦੇ ਹਨ।

ਆਪਣੇ useEffect hooks ਬਾਰੇ ਅੰਦਾਜ਼ੇ ਲਗਾਉਣਾ ਬੰਦ ਕਰੋ। ਇਹ ਜਾਣਨ ਦਾ ਇੱਕੋ ਇੱਕ ਤਰੀਕਾ ਕਿ ਕੋਈ ਲੀਕ ਹੈ ਜਾਂ ਨਹੀਂ, ਉਹ ਹੈ heap ਨੂੰ ਸਿੱਧਾ ਮਾਪਣਾ। Chrome DevTools ਤੁਹਾਨੂੰ ਉਹ ਸਪੱਸ਼ਟਤਾ (visibility) ਦਿੰਦਾ ਹੈ।

Chrome DevTools ਨਾਲ ਲੀਕਸ ਦੀ ਭਾਲ ਕਰਨਾ

ਤੁਹਾਨੂੰ ਇੱਕ ਦੁਹਰਾਉਣਯੋਗ (reproducible) ਲੜੀ ਅਤੇ ਕੁਝ ਮਿੰਟਾਂ ਦੇ ਕੇਂਦ੍ਰਿਤ ਧਿਆਨ ਦੀ ਲੋੜ ਹੈ। Chrome ਵਿੱਚ ਆਪਣੀ ਐਪਲੀਕੇਸ਼ਨ ਖੋਲ੍ਹੋ, DevTools ਚਲਾਓ, ਅਤੇ Memory tab 'ਤੇ ਜਾਓ।

ਇੱਕ baseline ਰਿਕਾਰਡ ਕਰੋ। Heap snapshot ਚੁਣੋ ਅਤੇ Take snapshot 'ਤੇ ਕਲਿੱਕ ਕਰੋ। ਇਹ JavaScript heap ਵਿੱਚ ਮੌਜੂਦਾ ਹਰ object ਨੂੰ ਕੈਪਚਰ ਕਰਦਾ ਹੈ ਅਤੇ ਤੁਹਾਨੂੰ ਸ਼ੁਰੂਆਤੀ ਮੈਮੋਰੀ ਦਿਖਾਉਂਦਾ ਹੈ। ਇਹ ਉਦੋਂ ਕਰੋ ਜਦੋਂ ਪੇਜ ਆਪਣੇ ਸ਼ੁਰੂਆਤੀ idle state ਵਿੱਚ ਸਥਿਰ ਹੋ ਜਾਵੇ, ਨਾ ਕਿ ਸ਼ੁਰੂਆਤੀ ਲੋਡ ਦੌਰਾਨ, ਤਾਂ ਜੋ ਤੁਸੀਂ ਸਿਰਫ਼ ਯੂਜ਼ਰ ਦੀਆਂ ਕਾਰਵਾਈਆਂ ਦੁਆਰਾ ਹੋਏ ਵਾਧੇ ਨੂੰ ਮਾਪ ਸਕੋ।

ਐਕਸ਼ਨ ਨੂੰ ਟ੍ਰਿਗਰ ਕਰੋ। ਉਹ ਸਹੀ UI ਇੰਟਰੈਕਸ਼ਨ ਕਰੋ ਜਿਸ ਬਾਰੇ ਤੁਹਾਨੂੰ ਸ਼ੱਕ ਹੈ ਕਿ ਉਹ ਲੀਕ ਦਾ ਕਾਰਨ ਬਣ ਰਿਹਾ ਹੈ। ਇੱਕ modal ਖੋਲ੍ਹੋ ਅਤੇ ਬੰਦ ਕਰੋ, ਇੱਕ ਗੁੰਝਲਦਾਰ ਚਾਰਟ ਨੂੰ toggle ਕਰੋ, ਜਾਂ ਰੂਟ ਬਦਲੋ ਅਤੇ ਵਾਪਸ ਜਾਓ। ਖਤਮ ਹੋਣ ਤੋਂ ਬਾਅਦ, ਐਪ ਨੂੰ ਇਸਦੀ ਅਸਲ ਵਿਜ਼ੂਅਲ ਸਥਿਤੀ ਵਿੱਚ ਵਾਪਸ ਲਿਆਓ। ਇਹ ਕਦਮ ਬਹੁਤ ਮਹੱਤਵਪੂਰਨ ਹੈ। ਤੁਸੀਂ ਚਾਹੁੰਦੇ ਹੋ ਕਿ UI ਬਿਲਕੁਲ ਉਹੀ ਦਿਖਾਈ ਦੇਵੇ ਜਿਵੇਂ ਕਿ baseline ਦੌਰਾਨ ਦਿਖਾਈ ਦੇ ਰਿਹਾ ਸੀ। ਜੇਕਰ UI ਖਾਲੀ ਦਿਖਣ ਦੇ ਬਾਵਜੂਦ heap ਵਧ ਗਿਆ ਹੈ, ਤਾਂ ਤੁਹਾਡੇ ਕੋਲ ਲੀਕ ਦਾ ਪੱਕਾ ਸਬੂਤ ਹੈ।

Garbage collection ਨੂੰ ਫੋਰਸ ਕਰੋ। Memory tab ਵਿੱਚ ਕੂੜੇਦਾਨ (trash can) ਆਈਕਨ 'ਤੇ ਕਲਿੱਕ ਕਰੋ। ਇਹ ਇੱਕ ਪੂਰਾ GC ਚੱਕਰ (cycle) ਸ਼ੁਰੂ ਕਰਦਾ ਹੈ ਅਤੇ ਉਹਨਾਂ ਅਸਥਾਈ objects ਨੂੰ ਸਾਫ਼ ਕਰਦਾ ਹੈ ਜੋ ਜਾਇਜ਼ ਤੌਰ 'ਤੇ ਅਗਲੇ collection ਤੱਕ ਬਚੇ ਰਹੇ ਸਨ। ਜੋ ਬਚਦਾ ਹੈ ਉਹ ਅਸਲੀ ਲੀਕਸ ਹਨ, ਉਹ objects ਜਿਨ੍ਹਾਂ ਨੂੰ ਇਕੱਠਾ (collect) ਕੀਤਾ ਜਾਣਾ ਚਾਹੀਦਾ ਸੀ ਪਰ ਗਲਤ references ਦੁਆਰਾ ਜਿਉਂਦਾ ਰੱਖਿਆ ਗਿਆ ਸੀ।

ਦੂਜਾ snapshot ਲਓ। ਫਿਰ ਤੋਂ Take snapshot 'ਤੇ ਕਲਿੱਕ ਕਰੋ। ਹੁਣ ਤੁਹਾਡੇ ਕੋਲ ਇੱਕੋ ਜਿਹੇ UI ਹਾਲਤਾਂ ਦੇ ਅਧੀਨ ਲਏ ਗਏ heap ਦੇ ਦੋ ਫੋਟੋਗ੍ਰਾਫ ਹਨ।

ਨਤੀਜਿਆਂ ਦੀ ਤੁਲਨਾ ਕਰੋ। View ਨੂੰ Summary ਤੋਂ Comparison ਵਿੱਚ ਬਦਲੋ। Baseline ਨੂੰ ਆਪਣੇ ਪਹਿਲੇ snapshot 'ਤੇ ਸੈੱਟ ਕਰੋ ਅਤੇ compared snapshot ਨੂੰ ਦੂਜੇ 'ਤੇ। Comparison view ਹਰ object category ਦੀ ਸੂਚੀ ਬਣਾਉਂਦਾ ਹੈ ਅਤੇ ਤੁਹਾਨੂੰ delta ਦਿਖਾਉਂਦਾ ਹੈ, ਜੋ ਦੋਵਾਂ ਕੈਪਚਰਾਂ ਵਿਚਕਾਰ object counts ਵਿੱਚ ਹੋਇਆ ਸ਼ੁੱਧ ਬਦਲਾਅ ਹੈ।

Delta ਅਨੁਸਾਰ sort ਕਰੋ। ਉਹਨਾਂ categories ਨੂੰ ਲੱਭੋ ਜੋ ਕਾਫ਼ੀ ਵਧ ਗਈਆਂ ਹਨ। ਖਾਸ ਤੌਰ 'ਤੇ Detached HTMLElement ਅਤੇ React fiber nodes 'ਤੇ ਧਿਆਨ ਦਿਓ। ਇੱਕ detached HTML element ਇੱਕ ਅਜਿਹਾ DOM node ਹੈ ਜੋ ਹੁਣ ਸਰਗਰਮ document tree ਨਾਲ ਨਹੀਂ ਜੁੜਿਆ ਹੋਇਆ ਹੈ, ਫਿਰ ਵੀ ਕੋਈ JavaScript reference ਅਜੇ ਵੀ ਇਸਨੂੰ ਫੜ ਕੇ ਰੱਖਦਾ ਹੈ। ਇਹ ਸਿੱਧੇ ਸਬੂਤ ਹਨ। ਮੋਡਲ ਬੰਦ ਕਰਨ ਜਾਂ ਕੰਪੋਨੈਂਟ ਨੂੰ unmount ਕਰਨ ਤੋਂ ਬਾਅਦ ਇਹਨਾਂ ਦਾ ਮੌਜੂਦ ਨਹੀਂ ਹੋਣਾ ਚਾਹੀਦਾ।

Retaining Path ਨੂੰ ਪੜ੍ਹਨਾ

ਜਦੋਂ ਤੁਸੀਂ snapshot ਵਿੱਚ ਇੱਕ detached element ਨੂੰ ਚੁਣਦੇ ਹੋ, ਤਾਂ Chrome ਹੇਠਲੇ ਪੈਨਲ ਵਿੱਚ retaining path ਦਿਖਾਉਂਦਾ ਹੈ। ਇਹ path ਰੂਟ (root) ਤੋਂ ਲੈ ਕੇ ਚੁਣੇ ਹੋਏ object ਤੱਕ ਦੇ references ਦੀ ਇੱਕ ਲੜੀ ਹੈ। ਇਸ ਨੂੰ ਧਿਆਨ ਨਾਲ ਫੋਲੋ ਕਰੋ। ਤੁਹਾਨੂੰ ਅਕਸਰ ਇੱਕ event listener, ਇੱਕ IntersectionObserver, ਇੱਕ setInterval ID, ਜਾਂ ਤੁਹਾਡੇ component ਦੀ ਕਿਸੇ ਖਾਸ ਲਾਈਨ ਵੱਲ ਇਸ਼ਾਰਾ ਕਰਨ ਵਾਲਾ ਇੱਕ closure ਮਿਲੇਗਾ।

ਉਹ ਨਾਮ ਲੱਭੋ ਜਿਨ੍ਹਾਂ ਨੂੰ ਤੁਸੀਂ ਪਛਾਣਦੇ ਹੋ। ਜੇਕਰ ਤੁਸੀਂ window ਨਾਲ ਜੁੜਿਆ ਹੋਇਆ ਕੋਈ listener ਦੇਖਦੇ ਹੋ ਜਿਸਦਾ function name ਤੁਹਾਡੇ codebase ਵਿੱਚੋਂ ਹੈ, ਤਾਂ ਤੁਹਾਨੂੰ anchor ਮਿਲ ਗਿਆ ਹੈ। ਉਹ object ਜੋ ਉਸ listener ਨੂੰ ਫੜ ਕੇ ਰੱਖ ਰਿਹਾ ਹੈ, ਤੁਹਾਡੇ ਪੂਰੇ component ਨੂੰ ਜਿਉਂਦਾ ਰੱਖ ਰਿਹਾ ਹੈ। ਕਦੇ-ਕਦੇ ਇਹ ਲੜੀ ਕਿਸੇ third-party library ਰਾਹੀਂ ਲੰਘਦੀ ਹੈ। ਅਜਿਹੇ ਮਾਮਲਿਆਂ ਵਿੱਚ, ਚੈੱਕ ਕਰੋ ਕਿ ਕੀ library ਇੱਕ explicit teardown call ਦੀ ਉਮੀਦ ਕਰਦੀ ਹੈ ਜੋ ਤੁਸੀਂ cleanup function ਵਿੱਚ ਕਰਨੀ ਭੁੱਲ ਗਏ ਹੋ।

ਮੂਲ ਕਾਰਨਾਂ ਨੂੰ ਠੀਕ ਕਰਨਾ

ਇੱਕ ਵਾਰ ਜਦੋਂ ਤੁਸੀਂ retaining path ਦੀ ਪਛਾਣ ਕਰ ਲੈਂਦੇ ਹੋ, ਤਾਂ ਇਸਦਾ ਹੱਲ ਆਮ ਤੌਰ 'ਤੇ mechanical ਹੁੰਦਾ ਹੈ ਪਰ ਇਸ ਲਈ ਪੂਰੀ team ਵਿੱਚ ਅਨੁਸ਼ਾਸਨ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ।

Cleanup functions ਦੀ ਵਰਤੋਂ ਕਰੋ। ਜਦੋਂ ਵੀ ਤੁਸੀਂ window ਜਾਂ document ਵਿੱਚ listeners ਜੋੜਦੇ ਹੋ, ਤਾਂ useEffect ਵਿੱਚ ਹਮੇਸ਼ਾ ਇੱਕ cleanup function return ਕਰੋ। ਜੇਕਰ ਤੁਹਾਡਾ effect ਕਿਸੇ resize event ਨੂੰ subscribe ਕਰਦਾ ਹੈ, ਤਾਂ component unmount ਹੋਣ ਤੋਂ ਪਹਿਲਾਂ ਉਸ subscription ਨੂੰ ਹਟਾ ਦਿਓ। Cleanup ਉਦੋਂ ਚੱਲਦਾ ਹੈ ਜਦੋਂ React component ਨੂੰ tear down ਕਰਦਾ ਹੈ, ਜੋ ਤੁਹਾਨੂੰ ਬਾਹਰੀ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਤੋੜਨ ਲਈ ਇੱਕ ਯਕੀਨੀ hook ਪ੍ਰਦਾਨ ਕਰਦਾ ਹੈ।

References ਨੂੰ ਸਥਿਰ (stabilize) ਕਰੋ। ਆਪਣੇ handlers ਨੂੰ useCallback ਵਿੱਚ ਲਪੇਟੋ (wrap ਕਰੋ)। ਇਹ ਯਕੀਨੀ ਬਣਾਉਂਦਾ ਹੈ ਕਿ ਤੁਸੀਂ removeEventListener ਨੂੰ ਉਹੀ function reference pass ਕਰੋ ਜੋ ਤੁਸੀਂ ਅਸਲ ਵਿੱਚ addEventListener ਨੂੰ pass ਕੀਤਾ ਸੀ। ਜੇਕਰ ਤੁਸੀਂ window.addEventListener('resize', () => { ... }) ਵਰਗਾ ਕੋਈ inline function register ਕਰਦੇ ਹੋ ਅਤੇ ਬਾਅਦ ਵਿੱਚ ਕਿਸੇ ਹੋਰ inline function ਨਾਲ ਇਸਨੂੰ ਹਟਾਉਣ ਦੀ ਕੋਸ਼ਿਸ਼ ਕਰਦੇ ਹੋ, ਤਾਂ references ਮੇਲ ਨਹੀਂ ਖਾਣਗੇ। Listener ਜੁੜਿਆ ਰਹੇਗਾ। ਇਸਦੇ ਅੰਦਰ ਦਾ closure ਤੁਹਾਡੇ component state ਨੂੰ ਜਿਉਂਦਾ ਰੱਖੇਗਾ। ਇੱਕ stable dependency array ਦੇ ਨਾਲ useCallback ਇਸ identity mismatch ਨੂੰ ਰੋਕਦਾ ਹੈ।

Global links ਨੂੰ ਤੋੜੋ। ਯਾਦ ਰੱਖੋ ਕਿ browser ਦੇ event target objects, ਜਿਵੇਂ ਕਿ window ਅਤੇ document, ਪੇਜ ਦੇ ਜੀਵਨ ਕਾਲ (lifetime) ਤੱਕ ਰਹਿੰਦੇ ਹਨ। ਉਹਨਾਂ ਤੋਂ ਤੁਹਾਡੇ component ਵਿੱਚ ਕੋਈ ਵੀ reference ਇੱਕ global anchor ਵਜੋਂ ਕੰਮ ਕਰਦਾ ਹੈ। Listener ਨੂੰ ਹਟਾਉਣ ਨਾਲ ਉਹ anchor ਟੁੱਟ ਜਾਂਦਾ ਹੈ ਅਤੇ V8 engine ਨੂੰ ਅਗਲੇ garbage collection cycle ਦੌਰਾਨ component state ਅਤੇ DOM nodes ਨੂੰ ਸਾਫ਼ ਕਰਨ ਦੀ ਇਜਾਜ਼ਤ ਮਿਲਦੀ ਹੈ।

ਇੱਕ ਅਜਿਹੇ modal ਬਾਰੇ ਸੋਚੋ ਜੋ window width ਨੂੰ track ਕਰਦਾ ਹੈ। Cleanup ਤੋਂ ਬਿਨਾਂ, ਹਰ ਵਾਰ ਜਦੋਂ user modal ਖੋਲ੍ਹਦਾ ਹੈ, ਇੱਕ ਨਵਾਂ listener ਜੁੜ ਜਾਂਦਾ ਹੈ। ਪੁਰਾਣੇ ਕਦੇ ਨਹੀਂ ਹਟਦੇ ਕਿਉਂਕਿ ਉਹ ਜਿਸ component instance ਨਾਲ ਸਬੰਧਤ ਹਨ ਉਹ ਖਤਮ ਹੋ ਚੁੱਕੇ ਹੁੰਦੇ ਹਨ, ਫਿਰ ਵੀ ਉਹ functions ਖੁਦ anonymous ਸਨ ਅਤੇ ਗੁੰਮ ਹੋ ਗਏ। useCallback ਵਿੱਚ ਲਪੇਟੇ ਹੋਏ ਇੱਕ named handler ਦੀ ਵਰਤੋਂ ਕਰਨ ਨਾਲ, ਅਤੇ ਇੱਕ cleanup function ਜੋ removeEventListener ਨੂੰ ਕਾਲ ਕਰਦਾ ਹੈ, ਇਸ ਚੱਕਰ ਨੂੰ ਸਾਫ਼ ਤਰੀਕੇ ਨਾਲ ਖਤਮ ਕਰਦਾ ਹੈ।

ਇੱਕ ਅਸਲ ਸਿੱਖਿਆ

React ਵਿੱਚ memory leaks ਬਹੁਤ ਘੱਟ ਹੀ ਕਿਸੇ ਸਪੱਸ਼ਟ error message ਨਾਲ ਆਪਣੀ ਮੌਜੂਦਗੀ ਦੱਸਦੇ ਹਨ। ਉਹ ਇੱਕ ਅਜਿਹੇ tab ਰਾਹੀਂ ਆਪਣੀ ਮੌਜੂਦਗੀ ਦੱਸਦੇ ਹਨ ਜੋ ਜਿੰਨਾ ਜ਼ਿਆਦਾ ਖੁੱਲ੍ਹਾ ਰਹਿੰਦਾ ਹੈ, ਉਨਾ ਹੀ ਭਾਰੀ ਹੁੰਦਾ ਜਾਂਦਾ ਹੈ। ਇਸ ਗੱਲ 'ਤੇ ਅੰਦਾਜ਼ਾ ਲਗਾਉਣ ਵਿੱਚ ਸਮਾਂ ਬਰਬਾਦ ਨਾ ਕਰੋ ਕਿ ਕਿਹੜਾ hook ਦੋਸ਼ੀ ਹੈ। Memory tab ਖੋਲ੍ਹੋ, garbage collection ਨੂੰ force ਕਰੋ, ਅਤੇ snapshots ਦੀ ਤੁਲਨਾ ਕਰੋ। Heap profiler ਨੂੰ ਤੁਹਾਨੂੰ ਸਹੀ retaining path ਦਿਖਾਉਣ ਦਿਓ। ਫਿਰ cleanup function ਲਿਖੋ, callback reference ਨੂੰ ਸਥਿਰ ਕਰੋ, ਅਤੇ global link ਨੂੰ ਤੋੜ ਦਿਓ। ਤੁਹਾਡੇ users ਇਸ ਸੁਧਾਰ ਨੂੰ ਸਿੱਧੇ ਤੌਰ 'ਤੇ ਨਹੀਂ ਦੇਖਣਗੇ, ਪਰ ਉਹ ਇਹ ਜ਼ਰੂਰ ਮਹਿਸੂਸ ਕਰਨਗੇ ਕਿ ਦਿਨ ਦੇ ਅੰਤ ਤੱਕ dashboard ਅਜੇ ਵੀ ਸੁਚਾਰੂ ਰੂਪ ਵਿੱਚ ਚੱਲ ਰਿਹਾ ਹੈ।