React’s useState Hook: The What, When, and Where of State Management

Abhishek KumarAbhishek Kumar
4 min read

The UseState hook in React is fundamental tool that allows you to add state to functional components. It enables components to manage and update state in response to user input, events, or other interactions.

What is useState Hook?

The useState hook provides a way to manage local state in functional component. It returns two values:

  • The current state and a function that updates the state.

  • The State can be of any type, such as numbers, strings, arrays, or objects.

const [state, setState] = useState(initialValue);
  • state: the current state value

  • setState: A function that updates the state.

  • initialValue: The initial value of the state ( can be any data type).

  • Example:

import React, { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // count starts at 0

  return (
    <div>
      <p>Current Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

export default Counter;

In the above example, the count variable holds the current state, and setCount is used to update the state when the button is clicked.

When to Use useState?

You should use useState when you need to :

  1. Track Local State: If your component needs to manage a piece of state that is independent of the rest of the application, such as form inputs, toggles, counter, etc.

  2. Handle User Interactions: When you need to update the UI based on user interactions (e.g., button clicks, types, etc.). It allows you to store the user’s input or response and reflect those changes in the component.

  3. Simple State Management: For small, self-contained state logic that doesn’t need to be shared across multiple components. For example, handling the visibility of a modal, toggling a dropdown, or switching between themes.

  4. Component-specific state: When the state only concerns a single component and is not required globally or across multiple components.

Here comes the best part, we should always be careful and known about when should we avoid the use of useState.

Where to Avoid using useState?

While useState is powerful, there are cases where you should avoid using it:

  1. Complex or Shared State:

    When state needs to be shared across multiple components: If your application has a state that needs to be accessed or modified by multiple components (e.g., user authentication state or theme settings), using useState in each component can lead to redundant or difficult-to-manage state. In such cases, consider using context (useContext) or a state management solution like Redux.

    For deeply nested state: If the state becomes complex, such as managing an object with many nested properties, managing updates with useState can become cumbersome. Using useReducer might be a better alternative in such cases.

    Example with useReducer :

const initialState = { count: 0 };

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return { count: state.count + 1 };
    case 'decrement':
      return { count: state.count - 1 };
    default:
      return state;
  }
}

const [state, dispatch] = useReducer(reducer, initialState);
  1. Global State Management:

    If you have data that needs to accessed throughout your application(e.g., user authentication status, theme, language preferences), it’s better to avoid useState in individual components and instead use global state solutions like Context API or external libraries like Redux and Zustand.

  2. Side Effects or Asynchronous Logic:

    If your state management involves side effects like fetching data from an API or interacting with external systems, it’s better to use useEffect in combination with useState rather than relying on useState alone.

  3. Performance concerns with Frequent Updates:

    If you have frequent updates (such as animations or real-time data), using useState might cause unnecessary re-renders and impact performance. In such cases, tools like Ref (useRef) can be more effiecient as it doesn’t trigger re-renders.

Best Practices with useState

  • Avoid Excessive Re-renders: Each time setState is called, the component re-renders. Try to minimize state changes to only what’s necessary.

  • Batch Updates: React batches updates made in event handlers. So, multiple setState calls within the same handler will trigger only one re-render.

  • Functional Updates: If you state update depends on the previous state, it’s better to use the functional form of setState.

setCount(prevCount => prevCount + 1);

Summary

When to use useState:

  • Managing local state in functional components.

  • Handling user input and UI interactions.

  • Managing simple state logic within a single component.

When to avoid using useState

  • When dealing with global state or shared data across multiple components.

  • When the state logic becomes too complex or deeply nested.

  • When performance might be affected by frequent re-renders (e.g., real-time updates).

  • When handling asynchronous or side effects alone ( should be paired with useEffect).

Thankyou for reading! connect with me on X/Twitter 🙌

0
Subscribe to my newsletter

Read articles from Abhishek Kumar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Abhishek Kumar
Abhishek Kumar

Hey there, a MERN Fullstack developer hailing from Kolkata, India. Talks/blogs about the same..