State
State is a concept in Class Component, in Funcitonal Component we use useState
1 2 | <span class="token keyword">const</span> <span class="token punctuation">[</span> state <span class="token punctuation">,</span> setState <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> initialStateValue <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
state
: defines the name of the state it can be single value or objectsetState
: defines the function name used to update the stateinitialStateValue
: is the initial value of state.
Typescript code we will write like this:
1 2 | <span class="token keyword">const</span> <span class="token punctuation">[</span> state <span class="token punctuation">,</span> setState <span class="token punctuation">]</span> <span class="token operator">=</span> useState <span class="token operator"><</span> string <span class="token operator">|</span> <span class="token keyword">undefined</span> <span class="token operator">></span> <span class="token punctuation">(</span> initialStateValue <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
State’s data type will be declared during state creation: <string | undefined>
What is useState used for?
it is used to store any value used in Component
this value will be killed when this component is no longer displayed
what parameter does useState take?
the only parameter it takes is the initialization value of state
What does useState return?
it returns 1 pair of values as array [state, funciton để thay đổi state]
If you don’t want to update the value, you can just leave the function: [state]
This way of writing applies the destructor of the new javascript
Note when using useState:
1. why do I have to use useState without declaring a normal variable in the Component? let state = initialStateValue; such as?
basically, use it or not depends on the case, using useState
will return a const variable, it will partially block the value of the state
using state will provide an object that lives for the lifetime of the Component, but a regular variable is unlikely
There was a case where I used let state = initialStateValue
instead of useState
, the result was that let state
received undifined
I don’t remember specifically, I don’t understand why but it’s clearly a lesson
I think using useState
is still better than declaring let state
, this type of local declaration should be used inside the function
2. create initialStateValue with callBack function
why use this way?
In some cases, the initialization value is not so easy to calculate, but React has to wait for the result to return before processing, which makes the Project feel like it’s frozen. To avoid such a case can consider applying return 1 callBack of this calculation:
1 2 3 | <span class="token keyword">const</span> <span class="token function-variable function">result</span> <span class="token operator">=</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">expensiveComputation</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> state <span class="token punctuation">,</span> setState <span class="token punctuation">]</span> <span class="token operator">=</span> useState <span class="token operator"><</span> string <span class="token operator">></span> <span class="token punctuation">(</span> result <span class="token punctuation">)</span> <span class="token punctuation">;</span> |
Lazy initial state
The initialState argument is the state used during the initial render.
In subsequent renders, it is disregarded.
If the initial state is the result of an expensive computation, you may provide a function instead
3. useState() use REPLACING instead of MERGING
if using setState(newVal) the old value will be lost, the new value will overwrite the old value
this won’t be a problem if the value is not Object, there will be 2 cases
- you will have to clone a new Object from the old Object and then update the necessary values: setPerson({ …person, color: ‘green’ });
- because state is Object, you can change the value inside Object normally: person.color = ‘green’;
pros and cons:
- The property of setState is to update slowly, which means:
line 10:setPerson({ ...person, color: 'green' });
line 11:person -> data vẫn chưa được update
it will not update until all the currently running functions run out, before re-gender it will update
Please apply this method if the data is used to display on the screen, do not need to use it immediately after updating - direct editing of Object like this does not go through the setState function
and of course it won’t trigger the re-gender function on the screen or other hooks like useEffect for example
Please use it if you want to get the new value to use immediately, apply it many times when submitting to prepare to switch pages
Unlike the setState method found in class components, useState does not automatically merge update objects. You can replicate this behavior by combining the function updater form with object spread syntax:
1 2 3 4 5 | <span class="token function">setState</span> <span class="token punctuation">(</span> <span class="token parameter">prevState</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token comment">// Object.assign would also work</span> <span class="token keyword">return</span> <span class="token punctuation">{</span> <span class="token operator">...</span> prevState <span class="token punctuation">,</span> <span class="token operator">...</span> updatedValues <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> |
Another option is useReducer, which is more suitable for managing state objects that contain multiple sub-values.
4. Update state using callback function
Instead of updating the state by passing in a new value, we can update the state by passing a callback function (with the old value as the argument) and returning the new value as the result. Eg:
1 2 | <span class="token function">setCount</span> <span class="token punctuation">(</span> <span class="token parameter">prevCount</span> <span class="token operator">=></span> prevCount <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> |
Using this way, when updating the state, it will ensure that the new value depends on the old value, not on the value of the state at the current time. Eg:
If the state is updated in the above way, then when the user presses the button many times within a period of 3 seconds, after 3 seconds the value of the state will only increase 1:
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setTimeout</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">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 comment">// Thay đổi state dựa theo giá trị của state hiện tại</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">3000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
If updating the state by passing in a function, in the 3 second delay, how many times the user presses the button, the value of the state will increase as much.
1 2 3 4 5 6 | <span class="token keyword">function</span> <span class="token function">handleClick</span> <span class="token punctuation">(</span> <span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token function">setTimeout</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">setCount</span> <span class="token punctuation">(</span> <span class="token parameter">prevCount</span> <span class="token operator">=></span> prevCount <span class="token operator">+</span> <span class="token number">1</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token comment">// Thay đổi state dựa theo giá trị của state trước đó</span> <span class="token punctuation">}</span> <span class="token punctuation">,</span> <span class="token number">3000</span> <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Thus, depending on the case, we will choose the appropriate way to use it.
5. why is <datatype> needed in useState<datatype>(initialStateValue)
==> this item is no longer active at the moment, my demo code is no longer reproducible, but everyone should still read for reference.
Assuming the object:
1 2 3 4 5 6 7 | <span class="token keyword">const</span> <span class="token punctuation">[</span> messageObj <span class="token punctuation">,</span> setMessage <span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span> <span class="token punctuation">(</span> <span class="token punctuation">{</span> message <span class="token operator">:</span> <span class="token string">''</span> <span class="token punctuation">,</span> id <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> onChange <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token parameter">e</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> newMessageObj <span class="token operator">=</span> <span class="token punctuation">{</span> message <span class="token operator">:</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 class="token function">setMessage</span> <span class="token punctuation">(</span> newMessageObj <span class="token punctuation">)</span> <span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token operator"><</span> strong <span class="token operator">></span> <span class="token punctuation">{</span> messageObj <span class="token punctuation">.</span> id <span class="token punctuation">}</span> <span class="token operator">:</span> <span class="token punctuation">{</span> messageObj <span class="token punctuation">.</span> message <span class="token punctuation">}</span> <span class="token operator"><</span> <span class="token operator">/</span> strong <span class="token operator">></span> |
after calling onChange
, setMessage
is called but the Object now contains only message
, and it still works properly, of course, the id
has been lost.
Clearly declaring the inner data type will avoid errors like this
6. Why in a useState state must be included in the dependency list of other Hooks, but not setState?
React guarantees that setState function identity is stable and won’t change on re-renders. This is why it’s safe to omit from the useEffect or useCallback dependency list.
in other words, state is mutable, but setState function is immutable, and React commits to this, so in Dependency Lists you will have to add state to check for changes, not setState function
conclusion
- useState is used to store data for the lifetime of the Component
- setState function will trigger re-render, but update value is slow, fix value through Object’s ref does not re-render, but value is fixed immediately
- The initial State and the update State can both be passed to the callback function, but you should be careful when to use it, be careful not to maintain