React
is a popular front-end library that is easy to learn. However, developers need to understand some concepts in order to write fast and performant code. This article details the caveats and concepts related to how states and effects work in React
.
derive the state
Sometimes we need to create a state variable that depends on another state variable. One way to do it is to use the useEffect
hook to update dependent state variables. For example, say you have a select element that displays a list of user IDs. I would like to track the selected user id in the userId
state variable. To do so, do the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span> <span class="token keyword">const</span> users <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token string">"1"</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"User One"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token string">"2"</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"User Two"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">{</span> id <span class="token operator">:</span> <span class="token string">"3"</span> <span class="token punctuation">,</span> name <span class="token operator">:</span> <span class="token string">"User Three"</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">]</span> <span class="token keyword">function</span> <span class="token function">Users</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> userId <span class="token punctuation">,</span> setUserId <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token string">"1"</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> select</span> <span class="token attr-name">value</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> userId <span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token function">setUserId</span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> target <span class="token punctuation">.</span> value <span class="token punctuation">)</span> <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 1 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User One</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 2 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Two</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 3 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Three</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> select</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now let’s say I want to display the selected user on the screen. You could create another state variable called selectedUser
and use the useEffect
hook to update it when the userId
changes.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <span class="token keyword">import</span> <span class="token punctuation">{</span> useState <span class="token punctuation">,</span> useEffect <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">"react"</span> <span class="token keyword">function</span> <span class="token function">Users</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> userId <span class="token punctuation">,</span> setUserId <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> selectedUser <span class="token punctuation">,</span> setSelectedUser <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token keyword">undefined</span> <span class="token punctuation">)</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setSelectedUser</span> <span class="token punctuation">(</span> users <span class="token punctuation">.</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token parameter">u</span> <span class="token operator">=></span> u <span class="token punctuation">.</span> id <span class="token operator">===</span> userId <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> userId <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> select</span> <span class="token attr-name">value</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> userId <span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token function">setUserId</span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> target <span class="token punctuation">.</span> value <span class="token punctuation">)</span> <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token punctuation">></span></span> <span class="token plain-text">Select a user</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 1 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User One</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 2 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Two</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 3 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Three</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> select</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> selectedUser <span class="token operator">&&</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The selected user is: </span><span class="token punctuation">{</span> selectedUser <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span></span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
This approach works, but it’s not the most efficient way to update selectedUser
. The problem with this method is that the component renders first when the userId
changes, after which the useEffect
hook is triggered, so the userId
is passed to the dependencies array. This means that the component will be rendered twice to update the selectedUser
, first when the userId
changes, and second time when the useEffect
hook updates the selectedUser
.
A better approach is to derive the value of selectedUser directly from userId.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <span class="token keyword">function</span> <span class="token function">Users</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> userId <span class="token punctuation">,</span> setUserId <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token string">""</span> <span class="token punctuation">)</span> <span class="token keyword">const</span> selectedUser <span class="token operator">=</span> users <span class="token punctuation">.</span> <span class="token function">find</span> <span class="token punctuation">(</span> <span class="token parameter">u</span> <span class="token operator">=></span> u <span class="token punctuation">.</span> id <span class="token operator">===</span> userId <span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> select</span> <span class="token attr-name">value</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> userId <span class="token punctuation">}</span></span> <span class="token attr-name">onChange</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token function">setUserId</span> <span class="token punctuation">(</span> e <span class="token punctuation">.</span> target <span class="token punctuation">.</span> value <span class="token punctuation">)</span> <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token punctuation">></span></span> <span class="token plain-text">Select a user</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 1 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User One</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 2 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Two</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> option</span> <span class="token attr-name">value</span> <span class="token attr-value"><span class="token punctuation attr-equals">=</span> <span class="token punctuation">"</span> 3 <span class="token punctuation">"</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">User Three</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> option</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> select</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> selectedUser <span class="token operator">&&</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The selected user is: </span><span class="token punctuation">{</span> selectedUser <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span></span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
This works because selectedUser
is derived directly from userId
and not tracked as a separate state variable. This means that the component will only re-render when the userId
changes, not twice as in the previous example.
Set state in event handler
Sometimes you need to update state inside event handlers such as click events or form submit events. In these cases it is important to ensure that state updates are performed asynchronously so that the component has a chance to re-render before the event handler has finished executing.
An example of how to set the state correctly inside an event handler:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">function</span> <span class="token function">Counter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> count <span class="token punctuation">,</span> setCount <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setCount</span> <span class="token punctuation">(</span> count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The count is: </span><span class="token punctuation">{</span> count <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">onClick</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> handleClick <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">Increment</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this example, we have a component called ” Counter
” that has a button that increments the count when clicked, displaying the count. handleClick
event handler uses the setCount
function to update the count
state variable.
It’s important to note that the setCount
function is asynchronous, meaning state updates may not be immediately reflected in the component. Instead, the component is re-rendered when the event handler finishes executing.
If you need to perform an operation that depends on the current state value, you can pass a function to the setCount
function. for example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">function</span> <span class="token function">Counter</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> count <span class="token punctuation">,</span> setCount <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token number">0</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token function-variable function">handleClick</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">setCount</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token parameter">currentCount</span> <span class="token punctuation">)</span> <span class="token operator">=></span> currentCount <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The count is: </span><span class="token punctuation">{</span> count <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">onClick</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> handleClick <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">Increment</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this example, the setCount
function is called with the current value of count
and a function that returns the new value. This ensures that state updates are performed correctly even if the component never gets a chance to re-render.
cleanup function
Sometimes we need to perform cleanup actions when a component is unmounted or some condition is no longer met. In these cases you can use a cleanup function with the useEffect
hook.
A cleanup function is a function that is called when a component is unmounted or a dependency in the useEffect
hook changes. This is a good place to do any necessary cleanup like canceling network requests or removing event listeners.
An example of how to use a cleanup function with the useEffect
hook:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | <span class="token keyword">function</span> <span class="token function">Users</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> userId <span class="token punctuation">,</span> setUserId <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> user <span class="token punctuation">,</span> setUser <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token function-variable function">fetchUser</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">/users/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> userId <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setUser</span> <span class="token punctuation">(</span> data <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">fetchUser</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Cleanup function</span> console <span class="token punctuation">.</span> <span class="token function">log</span> <span class="token punctuation">(</span> <span class="token string">"Cleaning up..."</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> userId <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">{</span> user <span class="token operator">?</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The user is: </span><span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token operator">:</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">Loading...</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">onClick</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setUserId</span> <span class="token punctuation">(</span> <span class="token number">2</span> <span class="token punctuation">)</span> <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">Load User 2</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this example, I have a component called Users
that retrieves users from the backend API based on the userId
state variable. A useEffect
hook is used to trigger a fetch when the userId
changes.
useEffect
hook also has a cleanup function that will be called if the component is unmounted or the userId
state variable has changed. In this case the cleanup function simply logs a message to the console.
Importantly, the cleanup function is only called when the dependencies in the useEffect
hook change or the component is unmounted. This means that if the userId
state variable changes but the useEffect
hook dependency does not, the cleanup function will not be called.
Update state when prop changes
Sometimes we need to update the component state based on the props passed to the component. In these cases you can use the useEffect
hook to detect when the prop changes and update the state accordingly.
An example of how to update the state when the prop changes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <span class="token keyword">function</span> <span class="token function">User</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> userId <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> user <span class="token punctuation">,</span> setUser <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token keyword">null</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">useEffect</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token function-variable function">fetchUser</span> <span class="token operator">=</span> <span class="token keyword">async</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> response <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token function">fetch</span> <span class="token punctuation">(</span> <span class="token template-string"><span class="token template-punctuation string">`</span> <span class="token string">/users/</span> <span class="token interpolation"><span class="token interpolation-punctuation punctuation">${</span> userId <span class="token interpolation-punctuation punctuation">}</span></span> <span class="token template-punctuation string">`</span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> data <span class="token operator">=</span> <span class="token keyword">await</span> response <span class="token punctuation">.</span> <span class="token function">json</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token function">setUser</span> <span class="token punctuation">(</span> data <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">;</span> <span class="token function">fetchUser</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> userId <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> user <span class="token operator">?</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The user is: </span><span class="token punctuation">{</span> user <span class="token punctuation">.</span> name <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token operator">:</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">Loading...</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this example, we have a component called ” User
” that retrieves the user from the backend API based on the userId
prop. A useEffect
hook is used to trigger a fetch when the userId
prop changes.
Importantly, the dependencies array in the useEffect hook should contain the props and state variables that the effect depends on. In this case, the effect depends on the userId
prop, so it’s included in the dependencies array.
If the useEffect
hook dependencies are not specified correctly, effects can be triggered unnecessarily, which can lead to performance issues.
save state at the same position
Sometimes I need to preserve the state of a component when redrawing the page in the same position. In these cases you can use the useMemo
useState
to save the state.
useMemo
hook is a performance optimization that allows values to be memoized so that they are only recomputed when dependencies change. This is useful for preserving component state when re-rendering in the same position.
An example of how to use the useMemo
hook to save component state:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token keyword">function</span> <span class="token function">Counter</span> <span class="token punctuation">(</span> <span class="token parameter"><span class="token punctuation">{</span> initialCount <span class="token punctuation">}</span></span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span> count <span class="token punctuation">,</span> setCount <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> initialCount <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">const</span> increment <span class="token operator">=</span> <span class="token function">useMemo</span> <span class="token punctuation">(</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">setCount</span> <span class="token punctuation">(</span> count <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token punctuation">[</span> count <span class="token punctuation">]</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> div</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> p</span> <span class="token punctuation">></span></span> <span class="token plain-text">The count is: </span><span class="token punctuation">{</span> count <span class="token punctuation">}</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> p</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span> button</span> <span class="token attr-name">onClick</span> <span class="token script language-javascript"><span class="token script-punctuation punctuation">=</span> <span class="token punctuation">{</span> increment <span class="token punctuation">}</span></span> <span class="token punctuation">></span></span> <span class="token plain-text">Increment</span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> button</span> <span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span> div</span> <span class="token punctuation">></span></span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
In this example, I have a component called “Counter”, with a button that increments the count when clicked, and displays the count. The ‘ increment
‘ function is created using the useMemo
hook and is only recalculated if the count
state variable changes. This means that the ‘ increment
‘ function will always have the correct value of ‘ count
‘ even if the ‘ Counter
‘ component is redrawn at the same position.
Importantly, the dependencies array of the useMemo
hook should contain the props and state variables that the memoized value depends on. In this case, the ‘ increment
‘ function depends on the count
state variable, so it is included in the dependencies array.
If the useMemo
hook dependencies are not specified correctly, memoized values can be recalculated unnecessarily, which can lead to performance issues.
Conclusion
We’ve talked about some concepts related to state and effects in React
. Deriving state, setting state in event handlers, using useEffect hooks and cleanup functions, updating state when props change, and re-rendering in the same position We’ve covered things like keeping component state.
Understanding these concepts is important for writing efficient and performant code in React, as well as understanding how states and effects work in the React
framework.
As always, I hope you enjoyed this article and learned something new.
Thank you very much. See you in the next article!
If you like this article, please support us by liking and subscribing. Thank you very much.