REACT

React State Management: Syntax, Usage, and Examples

React state management controls how data flows and updates across components in a React application. Managing state efficiently ensures that UI elements react correctly to user interactions and data changes without unnecessary re-renders.

How to Manage State in React

React offers multiple ways to manage state, ranging from built-in hooks like useState and useReducer to external libraries that help with global state. The best approach depends on your application's complexity and the level of state sharing between components.

Using useState for Local Component State

If your state only affects a single component, useState is the simplest way to manage it.

import React, { useState } from "react";

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

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

export default Counter;

The useState function initializes state, and the setCount function updates it when the user clicks the button.

Using useReducer for Complex State Logic

When your state logic grows, useReducer can provide better structure and clarity.

import React, { useReducer } from "react";

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;
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <div>
      <p>Count: {state.count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}

export default Counter;

This approach helps when state changes follow a structured pattern, such as form submissions or undo/redo functionality.

When to Use React State Management

Handling Local Component State

Use useState when a component needs to store and update simple data, such as input fields, toggles, or modals. Since useState only updates state within its component, it works well for UI elements that don’t need to share state with others.

Managing Global State Across Components

If multiple components need access to the same data, managing global state helps keep everything synchronized. Examples include:

  • Keeping a user logged in after authentication
  • Storing theme preferences across different pages
  • Managing cart data in an e-commerce application

Handling Server State

For real-time updates from an API, tools like React Query help fetch, cache, and sync server data efficiently. You might use this when handling search results, user profiles, or financial transactions that require live updates.

Examples of React State Management

Using React Context for Global State

React Context makes it easy to pass state between components without prop drilling.

import React, { createContext, useContext, useState } from "react";

const ThemeContext = createContext();

function ThemeProvider({ children }) {
  const [theme, setTheme] = useState("light");

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

function ThemedComponent() {
  const { theme, setTheme } = useContext(ThemeContext);

  return (
    <div style={{ background: theme === "light" ? "#fff" : "#333", color: theme === "light" ? "#000" : "#fff" }}>
      <p>Current Theme: {theme}</p>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Toggle Theme
      </button>
    </div>
  );
}

export default function App() {
  return (
    <ThemeProvider>
      <ThemedComponent />
    </ThemeProvider>
  );
}

Context helps when passing state deeply into multiple components, such as user authentication status or UI themes.

Using Redux for Large-Scale State Management

Redux is useful when your application requires a predictable, structured way to manage global state.

import { createStore } from "redux";
import { Provider, useDispatch, useSelector } from "react-redux";

const initialState = { count: 0 };

function counterReducer(state = initialState, action) {
  switch (action.type) {
    case "increment":
      return { count: state.count + 1 };
    case "decrement":
      return { count: state.count - 1 };
    default:
      return state;
  }
}

const store = createStore(counterReducer);

function Counter() {
  const count = useSelector((state) => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => dispatch({ type: "increment" })}>+</button>
      <button onClick={() => dispatch({ type: "decrement" })}>-</button>
    </div>
  );
}

function App() {
  return (
    <Provider store={store}>
      <Counter />
    </Provider>
  );
}

export default App;

Redux works well for enterprise-level applications where state needs to be accessed and updated from different parts of the application without direct component relationships.

Learn More About React State Management

Comparing Different State Management Approaches

Each state management approach has its strengths:

  • Use useState for local component state like form inputs or UI toggles.
  • Use useReducer when managing complex state logic, such as step-based forms or interactive UI elements.
  • Use React Context for lightweight global state needs, like themes or authentication.
  • Use Redux when multiple parts of an application require shared state updates, such as an online store's cart or user data.

Global State in React vs. Angular

React relies on hooks, Context API, and external libraries for state management. In contrast, Angular uses services and RxJS to handle global state changes. While React favors component-based reactivity, Angular integrates state management directly into its framework.

Choosing the Best State Management Approach

If your app is small, React’s built-in useState and Context API may be enough. If your project grows, libraries like Zustand or Recoil provide flexible state management without the complexity of Redux. When building a large-scale application, Redux or MobX help maintain a structured state architecture.

Storing State in Local Storage

To persist state across page reloads, use local storage:

import { useState, useEffect } from "react";

function App() {
  const [theme, setTheme] = useState(() => localStorage.getItem("theme") || "light");

  useEffect(() => {
    localStorage.setItem("theme", theme);
  }, [theme]);

  return (
    <div>
      <button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
        Toggle Theme
      </button>
    </div>
  );
}

export default App;

This method works well for preferences like dark mode or language settings.

Learn React for Free
Start learning now
button icon
To advance beyond this tutorial and learn React by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH