State Hooks
Hooks that remember information that is stored in components and refresh them when information is changed
For storing information in component use one of these Hooks:
useState
declares a state variable that you can update directly.useReducer
declares a state variable with the update logic inside a reducer function.
useState
Add a state variable to your component.
Parameters
-
initialState: The value you want the state to be initially. It can be a value of any type, but there is a special behavior for functions. This argument is ignored after the initial render.
- If you pass a function as initialState, it will be treated as an initializer function. It should be pure, should take no arguments, and should return a value of any type. React will call your initializer function when initializing the component, and store its return value as the initial state.
Returns
useState returns an array with exactly two values:
- The current state.
- The set function that lets you update the state to a different value and trigger a re-render.
Set function
-
The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the old value that was on the screen before your call.
-
If the new value is identical to the current state, React will skip re-rendering the component and its children.
-
React updates the screen after all the event handlers have run and have called their set functions. This prevents multiple re-renders during a single event. In the rare case that you need to force React to update the screen earlier, for example to access the DOM, you can use flushSync.
-
Calling the set function during rendering is only allowed from within the currently rendering component. See an example below.
-
State is considered read-only, so you should replace it rather then mutate your existing objects. don't mutate state
-
React saves the initial state once and ignores it on the next renders. don't call functions in initialState
-
You can reset a component’s state by passing a different key to a component. Resetting state with a key
Example: update value in current render
Example: Storing information from previous renders
Example: Updating objects and arrays in state
Example: Avoiding recreating the initial state
The result of createInitialTodos() is only used for the initial render, you’re still calling this function on every render. This can be wasteful if it’s creating large arrays or performing expensive calculations.
Example: Resetting state with a key
When the key changes, React re-creates the Form component (and all of its children) from scratch, so its state gets reset.
Example: How to store functions
This example below will call function
To store functions, you need to do something like this:
useReducer
This hook is similar to useState, but it is used when you have complext state logic. State is imutable.
Parameters
-
reducer: The reducer function that specifies how the state gets updated. Should take the state and action as arguments, and should return the next state. State and action can be of any types.
-
initialArg: The value from which the initial state is calculated. It can be a value of any type. How the initial state is calculated from it depends on the next init argument.
-
optional init: The initializer function that should return the initial state. If it’s not specified, the initial state is set to initialArg. Otherwise, the initial state is set to the result of calling init(initialArg).
Writing reducers well
-
Reducers must be pure. Similar to state updater function. reducers run during rendering! Actions should not send requests, schedule timeouts, or perform any side effects. They should update objects and arrays without mutations.
-
Each action describes a single user interaction, even if that leads to multiple changes in the data. For example, if a user presses "Reset" on a form with five fields managed by a reducer, it makes more sense to dispatch one reset_form action rather than five separate set_field actions. If you log every action in a reducer, that log should be clear enough for you to reconstruct what interactions or responses happened in what order.
Example: basic
Example: Todo
Example: Avoiding recreating the initial state
Example: Show calculated value in same function
You need to do two calculations.
useState vs useReducer
useState and useReducer differ from each other in the logic used to save state. useReducer uses the initialization logic you provided to determine how to save new data, whereas useState simply saves the data you provide.
It is recommended that you use a reducer if you often encounter bugs due to incorrect state updates in some components and want to introduce more structure to their code.
-
Code size: useReducer requires you to write both a reducer function and dispatch actions, but with useState you will not have to write that. However, useReducer can reduce the amount of code if numerous event handlers change state similarly.
-
Readability: useState is very easy to read when the state updates are simple. When they get more complex, they can bloat your component’s code and make it difficult to scan. In this case, useReducer lets you cleanly separate the how of update logic from the what happened of event handlers.
-
Debugging: When you have a bug with useState, it can be difficult to tell where the state was set incorrectly, and why. With useReducer, you can add a console log into your reducer to see every state update, and why it happened (due to which action).
-
Testing: A reducer is a pure function that doesn’t depend on your component. This means that you can export and test it separately in isolation.