ਜ਼ਿਆਦਾਤਰ React performance ਟਿਊਟੋਰਿਅਲ ਇੱਕੋ ਜਿਹੇ ਮਾੜੇ ਸਲਾਹ ਨਾਲ ਖਤਮ ਹੁੰਦੇ ਹਨ: ਹਰ ਚੀਜ਼ ਨੂੰ useMemo ਅਤੇ useCallback ਵਿੱਚ wrap ਕਰ ਦਿਓ ਅਤੇ ਆਪਣਾ ਕੰਮ ਮੁਕੰਮਲ ਸਮਝੋ। ਜੇਕਰ ਤੁਸੀਂ ਉਸ ਸਲਾਹ ਦੀ ਪਾਲਣਾ ਕੀਤੀ ਹੈ, ਤਾਂ ਸ਼ਾਇਦ ਤੁਸੀਂ ਆਪਣੀ ਐਪਲੀਕੇਸ਼ਨ ਨੂੰ ਹੋਰ ਵੀ ਹੌਲੀ ਕਰ ਦਿੱਤਾ ਹੈ। ਇਹ hooks ਮੁਫ਼ਤ ਨਹੀਂ ਹਨ। ਹਰ ਇੱਕ ਮੈਮੋਰੀ ਅਲਾਟ ਕਰਦਾ ਹੈ, dependencies ਦੀ ਤੁਲਨਾ ਕਰਦਾ ਹੈ, ਅਤੇ cached values ਨੂੰ ਸਟੋਰ ਕਰਦਾ ਹੈ। ਬਿਨਾਂ ਕਿਸੇ ਉਦੇਸ਼ ਦੇ ਵਰਤਣ 'ਤੇ, ਉਹ optimization ਦੀ ਬਜਾਏ overhead ਬਣ ਜਾਂਦੇ ਹਨ।
ਆਓ ਇਸ ਨੂੰ ਸਿਰਫ਼ ਉਸ ਤੱਕ ਸੀਮਤ ਕਰੀਏ ਜੋ ਅਸਲ ਵਿੱਚ ਮਾਇਨੇ ਰੱਖਦਾ ਹੈ।
ਹਰ Hook ਅਸਲ ਵਿੱਚ ਕੀ ਕਰਦਾ ਹੈ
useMemo ਇੱਕ value ਨੂੰ ਯਾਦ ਰੱਖਦਾ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਇੱਕ ਅਜਿਹਾ function ਦਿੰਦੇ ਹੋ ਜੋ ਭਾਰੀ ਕੰਮ (heavy work) ਕਰਦਾ ਹੈ, ਅਤੇ ਇਹ ਨਤੀਜਾ ਵਾਪਸ ਕਰਦਾ ਹੈ। ਅਗਲੇ render 'ਤੇ, ਜੇਕਰ ਤੁਹਾਡੀਆਂ dependencies ਨਹੀਂ ਬਦਲੀਆਂ ਹਨ, ਤਾਂ React ਗਣਨਾ (calculation) ਨੂੰ ਛੱਡ ਦਿੰਦਾ ਹੈ ਅਤੇ ਪੁਰਾਣਾ ਨਤੀਜਾ ਵਾਪਸ ਕਰ ਦਿੰਦਾ ਹੈ।
useCallback ਇੱਕ function ਨੂੰ ਯਾਦ ਰੱਖਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਲਈ function ਨੂੰ ਚਲਾਉਂਦਾ ਨਹੀਂ ਹੈ। ਇਹ ਸਿਰਫ਼ renders ਦੇ ਵਿਚਕਾਰ ਉਹੀ function instance ਵਾਪਸ ਕਰਦਾ ਹੈ ਜਦੋਂ ਤੱਕ ਇਸਦੀਆਂ dependencies ਉਹੀ ਰਹਿੰਦੀਆਂ ਹਨ।
ਇਹੀ ਪੂਰਾ ਅੰਤਰ ਹੈ। ਇੱਕ computed value ਨੂੰ cache ਕਰਦਾ ਹੈ। ਦੂਜਾ ਇੱਕ reference ਨੂੰ cache ਕਰਦਾ ਹੈ। ਇਹਨਾਂ ਨੂੰ ਮਿਲਾਉਣ ਨਾਲ ਅਜਿਹਾ ਕੋਡ ਬਣਦਾ ਹੈ ਜੋ optimized ਲੱਗਦਾ ਹੈ ਪਰ unwrapped ਕੋਡ ਵਾਂਗ ਹੀ ਕੰਮ ਕਰਦਾ ਹੈ ਅਤੇ ਵਾਧੂ ਮੈਮੋਰੀ ਦੀ ਵਰਤੋਂ ਕਰਦਾ ਹੈ।
Function Identity ਤੁਹਾਡੇ Tree ਨੂੰ ਕਿਉਂ ਤੋੜਦੀ ਹੈ
ਜਦੋਂ ਕੋਈ component re-render ਹੁੰਦਾ ਹੈ, ਤਾਂ React ਪੂਰੀ function body ਨੂੰ ਦੁਬਾਰਾ ਚਲਾਉਂਦਾ ਹੈ। ਹਰ variable ਨੂੰ ਦੁਬਾਰਾ ਬਣਾਇਆ ਜਾਂਦਾ ਹੈ। ਹਰ inline function ਨੂੰ ਮੈਮੋਰੀ ਵਿੱਚ ਇੱਕ ਬਿਲਕੁਲ ਨਵਾਂ ਪਤਾ (address) ਮਿਲਦਾ ਹੈ।
JavaScript ਵਿੱਚ, ਦੋ functions ਜਿਨ੍ਹਾਂ ਵਿੱਚ ਬਿਲਕੁਲ ਇੱਕੋ ਜਿਹੀ logic ਹੁੰਦੀ ਹੈ, ਉਹ ਬਰਾਬਰ ਨਹੀਂ ਹੁੰਦੇ। () => {} === () => {} ਦਾ ਨਤੀਜਾ false ਹੁੰਦਾ ਹੈ। ਇਹੀ ਨਿਯਮ objects ਅਤੇ arrays 'ਤੇ ਵੀ ਲਾਗੂ ਹੁੰਦਾ ਹੈ। ਜੇਕਰ ਤੁਹਾਡਾ parent component handleSubmit ਨੂੰ define ਕਰਦਾ ਹੈ ਅਤੇ ਇਸਨੂੰ ਇੱਕ child ਨੂੰ pass ਕਰਦਾ ਹੈ, ਤਾਂ ਉਹ child ਹਰ ਇੱਕ render 'ਤੇ ਇੱਕ ਨਵਾਂ prop ਪ੍ਰਾਪਤ ਕਰਦਾ ਹੈ। ਭਾਵੇਂ child React.memo ਵਿੱਚ wrapped ਹੋਵੇ, ਇਹ ਨਹੀਂ ਦੱਸ ਸਕਦਾ ਕਿ ਨਵਾਂ function ਪੁਰਾਣੇ function ਵਾਂਗ ਹੀ ਕੰਮ ਕਰਦਾ ਹੈ। Reference ਬਦਲ ਗਿਆ ਹੈ, ਇਸ ਲਈ child re-render ਹੁੰਦਾ ਹੈ।
ਇਹੀ ਉਹ ਮੂਲ ਸਮੱਸਿਆ ਹੈ ਜਿਸ ਨੂੰ ਹੱਲ ਕਰਨ ਲਈ useCallback ਬਣਾਇਆ ਗਿਆ ਸੀ। ਇਹ ਸਪੀਡ ਬਾਰੇ ਨਹੀਂ ਹੈ। ਇਹ stability ਬਾਰੇ ਹੈ।
useMemo ਕਦੋਂ ਫਾਇਦੇਮੰਦ ਹੁੰਦਾ ਹੈ
ਤੁਹਾਨੂੰ useMemo ਦੀ ਲੋੜ ਉਦੋਂ ਹੁੰਦੀ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਅਜਿਹਾ ਕੰਮ ਕਰ ਰਹੇ ਹੋ ਜੋ ਅਸਲ ਵਿੱਚ ਮਹਿੰਗਾ (expensive) ਹੈ ਅਤੇ ਤੁਸੀਂ ਇੱਕ ਮਾਪਣਯੋਗ (measurable) ਦੇਰੀ ਦੇਖ ਸਕਦੇ ਹੋ।
ਇੱਕ ਵਿਸ਼ਾਲ dataset ਨੂੰ filter ਕਰਨ ਬਾਰੇ ਸੋਚੋ। ਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਦਸ ਹਜ਼ਾਰਾਂ rows ਵਾਲੀ ਇੱਕ table ਅਤੇ ਇੱਕ search input ਹੈ, ਤਾਂ ਤੁਸੀਂ ਆਪਣੇ component ਦੇ ਅੰਦਰ ਕੁਝ ਇਸ ਤਰ੍ਹਾਂ ਲਿਖ ਸਕਦੇ ਹੋ:
const visibleRows = rows.filter(r => r.name.includes(query));
useMemo ਤੋਂ ਬਿਨਾਂ, ਉਹ loop ਹਰ render 'ਤੇ ਚੱਲਦਾ ਹੈ। ਜੇਕਰ ਉਪਭੋਗਤਾ (user) ਕਿਸੇ ਅਜਿਹੇ ਬਟਨ 'ਤੇ ਕਲਿੱਕ ਕਰਦਾ ਹੈ ਜੋ sidebar ਨੂੰ toggle ਕਰਦਾ ਹੈ, ਤਾਂ parent re-render ਹੁੰਦਾ ਹੈ, ਅਤੇ ਤੁਹਾਡਾ filter ਦੁਬਾਰਾ ਚੱਲਦਾ ਹੈ ਭਾਵੇਂ rows ਅਤੇ query ਕਦੇ ਬਦਲੇ ਹੀ ਨਹੀਂ। ਇੱਕ ਵੱਡੇ dataset 'ਤੇ, ਉਹ ਰੁਕਾਵਟ (stutter) ਸਾਫ਼ ਦਿਖਾਈ ਦਿੰਦੀ ਹੈ।
useMemo ਨਤੀਜੇ ਨੂੰ fix ਕਰਕੇ ਇਸਨੂੰ ਠੀਕ ਕਰਦਾ ਹੈ:
const visibleRows = useMemo(() => {
return rows.filter(r => r.name.includes(query));
}, [rows, query]);
ਹੁਣ React ਉਸ filter ਨੂੰ ਉਦੋਂ ਹੀ ਦੁਬਾਰਾ ਚਲਾਉਂਦਾ ਹੈ ਜਦੋਂ dependencies ਅਸਲ ਵਿੱਚ ਬਦਲਦੀਆਂ ਹਨ।
ਇਹੀ ਤਰਕ (logic) ਗੁੰਝਲਦਾਰ ਗਣਿਤਕ ਗਣਨਾਵਾਂ (mathematical calculations), API responses ਨੂੰ chart-friendly formats ਵਿੱਚ ਬਦਲਣ, ਜਾਂ ਅਜਿਹੀ state ਕੱਢਣ ਲਈ ਵੀ ਲਾਗੂ ਹੁੰਦਾ ਹੈ ਜਿਸ ਨੂੰ ਨਹੀਂ ਤਾਂ ਲਗਾਤਾਰ ਦੁਬਾਰਾ ਗਣਨਾ ਕੀਤੀ ਜਾਂਦੀ।
ਇੱਕ ਦੂਜਾ, ਘੱਟ ਸਪੱਸ਼ਟ use case ਵੀ ਹੈ। ਜੇਕਰ ਤੁਸੀਂ ਸਥਾਨਕ (locally) ਤੌਰ 'ਤੇ ਇੱਕ object ਜਾਂ array ਬਣਾਉਂਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ useEffect dependency array ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਗਲਤੀ ਨਾਲ ਹਰ render 'ਤੇ ਉਸ effect ਨੂੰ trigger ਕਰ ਸਕਦੇ ਹੋ। Inline objects ਅਤੇ arrays ਹਰ ਵਾਰ ਨਵੀਂ identity ਪ੍ਰਾਪਤ ਕਰਦੇ ਹਨ, ਇਸ ਲਈ effect ਇੱਕ ਬਦਲੀ ਹੋਈ dependency ਦੇਖਦਾ ਹੈ ਅਤੇ ਦੁਬਾਰਾ ਚੱਲਦਾ ਹੈ। ਉਸ object ਨੂੰ useMemo ਨਾਲ memoize ਕਰਨ ਨਾਲ reference stable ਰਹਿੰਦਾ ਹੈ ਅਤੇ ਤੁਹਾਡਾ effect ਉਦੋਂ ਹੀ ਚੱਲਦਾ ਹੈ ਜਦੋਂ ਅਸਲ ਡੇਟਾ ਬਦਲਦਾ ਹੈ।
useCallback ਕਦੋਂ ਜ਼ਰੂਰੀ ਹੋ ਜਾਂਦਾ ਹੈ
useCallback ਸਭ ਤੋਂ ਵੱਧ ਉਦੋਂ ਮਾਇਨੇ ਰੱਖਦਾ ਹੈ ਜਦੋਂ ਤੁਸੀਂ ਉਹ handlers child components ਵਿੱਚ pass ਕਰ ਰਹੇ ਹੁੰਦੇ ਹੋ ਜੋ React.memo ਨਾਲ optimized ਕੀਤੇ ਗਏ ਹਨ।
ਇੱਕ parent component ਦੀ ਕਲਪਨਾ ਕਰੋ ਜਿਸ ਵਿੱਚ ਇੱਕ counter ਹੈ। ਇਹ ਇੱਕ ਮਹਿੰਗੀ (expensive) child list ਨੂੰ ਵੀ render ਕਰਦਾ ਹੈ:
function Parent() {
const [count, setCount] = useState(0);
const handleItemClick = (id) => {
console.log(id);
};
return (
<div>
<button onClick={() => setCount(c + 1)}>{count}</button>
<ExpensiveList onItemClick={handleItemClick} />
</div>
);
}
ਹਰ ਵਾਰ ਜਦੋਂ count ਬਦਲਦਾ ਹੈ, Parent re-render ਹੁੰਦਾ ਹੈ। ਇੱਕ ਨਵਾਂ handleItemClick ਬਣਾਇਆ ਜਾਂਦਾ ਹੈ। ਕਿਉਂਕਿ ExpensiveList ਨੂੰ ਇੱਕ ਨਵਾਂ prop reference ਮਿਲਦਾ ਹੈ, ਇਸ ਲਈ ਇਹ ਵੀ re-render ਹੁੰਦਾ ਹੈ। ਜੇਕਰ ExpensiveList ਨੂੰ React.memo ਵਿੱਚ wrap ਕੀਤਾ ਗਿਆ ਹੈ, ਤਾਂ ਉਹ memoization ਪੂਰੀ ਤਰ੍ਹਾਂ ਬੇਕਾਰ ਹੈ ਕਿਉਂਕਿ function prop ਬਦਲ ਗਿਆ ਹੈ।
useCallback reference ਨੂੰ ਬਚਾ ਕੇ ਰੱਖਦਾ ਹੈ:
const handleItemClick = useCallback((id) => {
console.log(id);
}, []);
ਹੁਣ ExpensiveList ਉਦੋਂ ਹੀ re-render ਹੁੰਦਾ ਹੈ ਜਦੋਂ ਇਸਨੂੰ ਸੱਚਮੁੱਚ ਲੋੜ ਹੁੰਦੀ ਹੈ।
ਇੱਕ ਹੋਰ ਮਹੱਤਵਪੂਰਨ ਸਥਿਤੀ useEffect ਨਾਲ ਸਬੰਧਤ ਹੈ। ਜੇਕਰ ਕੋਈ effect ਤੁਹਾਡੇ component ਦੇ ਅੰਦਰ ਮਿਲੇ ਇੱਕ function ਨੂੰ subscribe ਕਰਦਾ ਹੈ, ਅਤੇ ਉਹ function ਹਰ render 'ਤੇ ਆਪਣੀ identity ਬਦਲਦਾ ਹੈ, ਤਾਂ effect ਵਾਰ-ਵਾਰ teardown ਹੋਵੇਗਾ ਅਤੇ ਦੁਬਾਰਾ subscribe ਹੋਵੇਗਾ। Function ਨੂੰ memoize ਕਰਨ ਨਾਲ effect stable ਰਹਿੰਦਾ ਹੈ।
Dependency Array ਦਾ ਜਾਲ ਅਤੇ Stale Closures
ਦੋਵੇਂ hooks dependency arrays 'ਤੇ ਨਿਰਭਰ ਕਰਦੇ ਹਨ, ਅਤੇ ਇੱਥੇ ਹੀ ਜ਼ਿਆਦਾਤਰ bugs ਲੁਕੇ ਹ
ਜੇਕਰ ਤੁਸੀਂ dependency array ਵਿੱਚੋਂ ਕਿਸੇ ਵੇਰੀਏਬਲ ਨੂੰ ਛੱਡ ਦਿੰਦੇ ਹੋ, ਤਾਂ ਤੁਹਾਡਾ memoized function ਜਾਂ value ਉਸ ਵੇਰੀਏਬਲ ਦੇ ਪੁਰਾਣੇ ਵਰਜ਼ਨ ਨੂੰ ਕੈਪਚਰ ਕਰ ਲੈਂਦੀ ਹੈ। ਇਸਨੂੰ stale closure ਕਿਹਾ ਜਾਂਦਾ ਹੈ। UI ਸ਼ਾਇਦ ਤਾਜ਼ਾ ਡੇਟਾ ਦਿਖਾ ਰਿਹਾ ਹੋਵੇ, ਪਰ ਤੁਹਾਡਾ callback ਅਜੇ ਵੀ ਤਿੰਨ renders ਪਹਿਲਾਂ ਵਾਲੇ state ਨੂੰ ਦੇਖ ਰਿਹਾ ਹੁੰਦਾ ਹੈ। ਇਸਦਾ ਹੱਲ ਸਧਾਰਨ ਹੈ ਪਰ code reviews ਦੌਰਾਨ ਇਸਨੂੰ ਨਜ਼ਰਅੰਦਾਜ਼ ਕਰਨਾ ਆਸਾਨ ਹੈ: hook ਦੇ ਅੰਦਰ ਵਰਤੇ ਗਏ ਹਰ ਉਸ ਮੁੱਲ (value) ਨੂੰ ਸ਼ਾਮਲ ਕਰੋ ਜੋ ਬਦਲ ਸਕਦਾ ਹੈ।
react-hooks/exhaustive-deps ESLint rule ਨੂੰ ਚਲਾਓ। ਇਹ ਸਪੱਸ਼ਟ ਗਲਤੀਆਂ ਨੂੰ ਫੜ ਲਵੇਗਾ। ਪਰ ਇਸਨੂੰ ਇੱਕ ਰੋਬੋਟ ਵਾਂਗ ਨਾ ਸਮਝੋ। ਇਹ ਸਮਝੋ ਕਿ ਕਿਉਂ ਹਰ dependency ਮਹੱਤਵਪੂਰਨ ਹੈ।
Over-Optimization ਦਾ ਲੁਕਿਆ ਹੋਇਆ ਟੈਕਸ
ਸ਼ੁਰੂਆਤ ਕਰਨ ਵਾਲੇ ਅਕਸਰ ਹਰ function ਅਤੇ ਹਰ value ਨੂੰ ਇਹਨਾਂ hooks ਨਾਲ ਕਵਰ ਕਰ ਦਿੰਦੇ ਹਨ ਕਿਉਂਕਿ ਇਹ ਸੁਰੱਖਿਅਤ ਮਹਿਸੂਸ ਹੁੰਦਾ ਹੈ। ਇਹ ਆਦਤ ਉਲਟਾ ਨਤੀਜਾ ਦੇ ਸਕਦੀ ਹੈ।
React ਨੂੰ memory ਵਿੱਚ cached values ਨੂੰ ਸਟੋਰ ਕਰਨਾ ਪੈਂਦਾ ਹੈ। ਹਰ render 'ਤੇ, ਇਸਨੂੰ ਤੁਹਾਡੇ dependency array ਵਿੱਚੋਂ ਲੰਘਣਾ ਪੈਂਦਾ ਹੈ ਅਤੇ Object.is ਦੀ ਵਰਤੋਂ ਕਰਕੇ ਹਰੇਕ ਆਈਟਮ ਦੀ ਤੁਲਨਾ ਕਰਨੀ ਪੈਂਦੀ ਹੈ। ਉਹ ਤੁਲਨਾ ਸਸਤੀ ਹੈ, ਪਰ ਇਹ ਮੁਫ਼ਤ ਨਹੀਂ ਹੈ। ਜੇਕਰ ਤੁਸੀਂ onClick={() => setOpen(true)} ਵਰਗੇ ਇੱਕ ਮਾਮੂਲੀ event handler ਨੂੰ useCallback ਦੇ ਅੰਦਰ ਲਪੇਟਦੇ ਹੋ, ਤਾਂ ਤੁਸੀਂ ਇੱਕ ਅਜਿਹਾ function ਬਣਾਉਣ ਤੋਂ ਬਚਣ ਲਈ memory ਅਤੇ CPU ਦੀ ਕੀਮਤ ਚੁਕਾ ਰਹੇ ਹੋ ਜੋ ਬਹੁਤ ਹੀ ਤੇਜ਼ੀ ਨਾਲ ਬਣ ਸਕਦਾ ਸੀ।
Hooks ਵਾਧੂ ਗੜਬੜ (noise) ਵੀ ਪੈਦਾ ਕਰਦੇ ਹਨ। useMemo ਅਤੇ useCallback ਵਿੱਚ ਲਪੇਟਿਆ ਹੋਇਆ code ਪੜ੍ਹਨਾ ਅਤੇ ਇਸਨੂੰ ਬਣਾਈ ਰੱਖਣਾ (maintain) ਮੁਸ਼ਕਲ ਹੁੰਦਾ ਹੈ। ਹਰ dependency array ਇੱਕ ਸੰਭਾਵਿਤ stale closure ਹੈ ਜੋ ਤੁਹਾਨੂੰ ਨੁਕਸਾਨ ਪਹੁੰਚਾਉਣ ਲਈ ਤਿਆਰ ਬੈਠਾ ਹੈ।
ਅਸਲ ਨਿਯਮ (rule of thumb) ਸ਼ਾਨਦਾਰ ਨਹੀਂ ਹੈ ਪਰ ਪ੍ਰਭਾਵਸ਼ਾਲੀ ਹੈ: ਪਹਿਲਾਂ ਸਾਧਾਰਨ code ਲਿਖੋ। ਸਿਰਫ਼ ਉਦੋਂ ਹੀ optimize ਕਰੋ ਜਦੋਂ ਤੁਹਾਡੇ ਕੋਲ ਕਿਸੇ ਸਮੱਸਿਆ ਦਾ ਸਬੂਤ ਹੋਵੇ। ਇਹ ਪਛਾਣਨ ਲਈ ਕਿ ਕਿਹੜੇ components ਮਹਿੰਗੇ ਹਨ ਅਤੇ ਕਿਹੜੇ renders ਫਾਲਤੂ ਹਨ, React DevTools Profiler ਦੀ ਵਰਤੋਂ ਕਰੋ। ਜੇਕਰ ਇੱਕ render ਕੁਝ ਮਿਲੀਸੈਕਿੰਡ ਤੋਂ ਵੀ ਘੱਟ ਸਮਾਂ ਲੈਂਦਾ ਹੈ, ਤਾਂ ਕੋਈ ਵੀ ਉਪਭੋਗਤਾ ਇਸਨੂੰ ਨੋਟ ਨਹੀਂ ਕਰੇਗਾ, ਅਤੇ ਤੁਹਾਡੀ memoization ਕੁਝ ਵੀ ਹੱਲ ਨਹੀਂ ਕਰ ਰਹੀ।
ਨਿਚੋੜ
useMemo ਮਹਿੰਗੀਆਂ values ਲਈ ਹੈ। useCallback ਸਥਿਰ (stable) function references ਲਈ ਹੈ। ਕੋਈ ਵੀ hook ਆਪਣੇ ਆਪ ਤੁਹਾਡੇ component ਦੇ render ਨੂੰ ਤੇਜ਼ ਨਹੀਂ ਕਰਦਾ; ਉਹ ਅਣਜਾਣ downstream ਕੰਮ ਨੂੰ ਰੋਕਦੇ ਹਨ। ਉਹਨਾਂ ਤੋਂ ਬਿਨਾਂ ਸ਼ੁਰੂ ਕਰੋ, ਅਸਲ tooling ਨਾਲ ਮਾਪੋ, ਅਤੇ ਉਹਨਾਂ ਨੂੰ ਉੱਥੇ ਹੀ ਜੋੜੋ ਜਿੱਥੇ profiler bottleneck ਦਿਖਾਉਂਦਾ ਹੈ। ਸਾਫ਼ code ਜੋ ਕਦੇ-ਕਦੇ rerender ਹੁੰਦਾ ਹੈ, ਉਹ ਹਮੇਸ਼ਾ ਉਸ over-engineered code ਨਾਲੋਂ ਬਿਹਤਰ ਹੋਵੇਗਾ ਜੋ ਹਰ ਚੀਜ਼ ਨੂੰ memoize ਕਰਦਾ ਹੈ।
