React Hooks Cheat Sheets — 1: useState Hook

Vinod Madubashana
unibench
Published in
4 min readFeb 2, 2024

What is useState hook?

  • The most used hook that gives the capability to store component state variables across multiple renders and rerender the component when the value changes.
  • Here rendering means not actual browser rendering, it is about executing our component function and creating a new fiber tree (Also known as virtual DOM). The actual rendering happens only if a change is detected between the existing and new trees.

Example and Mechanics

  • The example code available in this Github repo, in the branch useState-hook
  • See the below Counter component which shows a simple counter using a state variable and function scoped local variable which increases when the button clicks.
import { useState } from "react";

function App() {
const [count, setCount] = useState(0); // -----------------> 1
// const [count, setCount] = useState(() => 0); // --------> 2

let count2 = 1; // -----------------------------------------> 3
function handleIncrease() {
setCount((count) => count + 1); // ----------------------> 4
// setCount(count + 1); // -------------------------------> 5
count2 += 1; // ------------------------------------------> 6
}

return (
<div className="mt-5 flex flex-col items-center justify-center">
<button
onClick={handleIncrease}
className=" w-40 rounded-full bg-orange-300 px-2 py-4"
>
Increase Count
</button>
<div className="mt-2">
{count} - {count2}
</div>
{/* <Child count={count} count2={count2} />; */}
</div>
);
}

1. Calling useState hook

  • In 1 shows the use of the useState function which takes the initial value as the first argument and returns an array of state variable and updater function.
  • As a best practice, javascript array destructuring is used to extract these into const variables.
  • It is possible to get these into mutable variables using let and change the value of the state variable directly, but it will not rerender the component which means no value and can cause hard-to-debug issues.
  • The option to update the value is the updater function which updates the state variable value and makes sure it will not reset when rerendering the component.
  • This is true only as the component rerenders while it is in the actual dom. If the component is completely removed from the dom and reentered then the state value is set back to the initial value. So this is only can be used for local state management.
  • The updater function also keeps its identity over the re-rerenders, which means it can be used safely in the dependency array of some hooks like useEffect without using useCallback hook.

2. Using a function to calculate the initial value

  • useState hook has an alternate method that accepts a function to set the initial value.
  • This can be used where some logic is there to calculate the initial value, for example using values of props
  • Important Note: The initial value will not be re-calculated in re-renders. It only runs at the first render.

3. Experiment with local variable

  • Local variables always reset when re-renders.

4. Update value using the updater function

  • As a best practice use the updater function by passing another function that takes the current value and returns the new value
  • The execution of the updater function is asynchronous. Hence if we access the state variable after just an update will not reflect the updated value. (React also batches these operations to improve performance by reducing required re-renders.)
  • Can call multiple times safely with this approach

5. Using the updater function by passing a new value

  • This is the most common way of updating simple changes.
  • But still prefer the use of function instead of this.
  • multiple calls with updating using the state variable will not work, because the executions are bathed and executed asynchronously.

6. Local variables always reset with re-renders

  • The update will be lost when the component re-renders.

When to use

  • To manage component local state.
  • Examples — counters, loading state, loaded data related to a local query, etc. (Some of these states might be better to keep in a global state if they are reusable across components.)

When not to use

  • Track global state
  • Derived state — simply use a const state variable, for example, if you need a square of count in the above example, don’t use useState to initiate state and update it in multiple places where count changes. Simply use const square = count ^ 2 inside your function component. When the count state changes it re-runs the function code which updates the derived state correctly.
  • Constant values — These can be defined as const variables and to avoid the recreation of the same object again and again these can be defined outside the function scope.
  • When the state changes and doesn't need to re-render — This is also cant achieved with the function scope variable. The situation that required these state variables and the solution will be discussed in a later article. (useRef hook)

Key points to remember

  • Don’t update the state variable directly, always use the updater function.
  • The updates are asynchronous and batched.
  • Prefer the passing function over the direct value in the updater function. This simplifies work with new values within this function if needed also works fine when multiple executions happen within the same method.
  • Remember that the initial value is only used at the first render of the component.
  • More suitable for primitive state values like strings, booleans, and numbers.
  • If the state variable is an object then make sure to create a new object when the state updates, for example, can use modern javascript object syntax like {…state, key: newVal} to create an object from the existing one with changed values and use the updater function to update.

--

--

Vinod Madubashana
unibench

Full-stack Developer, Java, Spring Boot, React, Angular, AWS ...