DEV Community

Cover image for State Management in the Frontend: Understanding the Context API
Kelvin Almeida
Kelvin Almeida

Posted on

2 1

State Management in the Frontend: Understanding the Context API

What is state management

State management is the process of controlling and managing the data of an application. In the frontend, it means keeping the information that influences the rendering of the interface up to date. For example, when we are typing in a form, whether a modal is open, or which items are in the shopping cart.

What is state in a frontend application?

State is any information that changes over time while interacting with the application. One example is the text typed in a search field; another example is when we click a button and a modal opens.

Difference between local state and global state

Local state is limited to a single component, such as a button that changes color when clicked.

Global state is shared by multiple components, such as user data that can be accessed throughout the application.

Simple example with useState

The counter state is local. It only affects the Counter component.

import { useState } from 'react';

function Counter() {
  const [counter, setCounter] = useState(0);

  return (
    <div>
      <p>You clicked {counter} times</p>
      <button onClick={() => setCounter(counter + 1)}>Click</button>
    </div>
  );
}

Enter fullscreen mode Exit fullscreen mode

Why is useState sometimes not enough?

Now imagine an application with several components that need to access or modify the same data. This is where problems with useState begin, such as passing many props from one component to another. We need to lift the state to a common parent component, which makes the code structure hard to scale and maintain.

Simple example of the problem:

function App() {
  const [user, setUser] = useState(null);

  return (
    <>
      <Header user={user} />
      <Sidebar user={user} />
      <Dashboard user={user} />
    </>
  );
}

Enter fullscreen mode Exit fullscreen mode

If you need to modify user inside Dashboard, we will also need to pass setUser, and this is where things start to get messy in larger projects. That's why solutions like Context API, Redux, and Zustand come into play, as they solve these problems by providing global state in an organized manner.

How does the Context API solve the problem?

Going back to the previous example, where user had to be passed through props to multiple components, with the Context API, we can create a context, provide the context value in a parent component, and consume the value in any child component.

Basic example with Context API

Creating the UserContext.js context using createContext.

import { createContext } from 'react';

export const UserContext = createContext(null);

Enter fullscreen mode Exit fullscreen mode

After creating our context, we wrap our root component with the provider, sharing the data via the value property.

// App.js
import { useState } from 'react';
import { UserContext } from './UserContext';
import Header from './Header';
import Dashboard from './Dashboard';

function App() {
  const [user, setUser] = useState({ name: 'John' });

  return (
    <UserContext.Provider value={{ user, setUser }}>
      <Header />
      <Dashboard />
    </UserContext.Provider>
  );
}

Enter fullscreen mode Exit fullscreen mode

Using in any component:

// components/Header.js
import { useContext } from 'react';
import { UserContext } from '../context/UserContext';

function Header() {
  const { user } = useContext(UserContext);

  return (
    <header>
      <p>Welcome, {user.name}!</p>
    </header>
  );
}

export default Header;

Enter fullscreen mode Exit fullscreen mode

Advantages of using Context API

  • We don't need external libraries since it's native to React.

  • Great for simple shared data such as theme, language, and authentication.

  • We avoid passing props in a chain, keeping the application clean and organized.

Disadvantages and limitations

  • When the value of a context changes, all components that use that context will re-render, even if only part of the state has changed.
  • Lack of debugging tools, middlewares, and management of complex asynchronous actions such as API calls with loading and error states can become messy.
  • As we add more Context Providers to split the state into smaller pieces, our application can start to look like a mess of providers. For example:
<ThemeContext.Provider>
  <LanguageContext.Provider>
    <UserContext.Provider>
      <CartContext.Provider>
        <App />
      </CartContext.Provider>
    </UserContext.Provider>
  </LanguageContext.Provider>
</ThemeContext.Provider>

Enter fullscreen mode Exit fullscreen mode

This can make the code harder to maintain and read.

Conclusion

State management is essential for maintaining consistency and smoothness in our frontend applications. The Context API is a great native solution for simple global states, but if we're dealing with very large or complex applications with many state updates, it might be better to use solutions like Zustand and Redux.

Heroku

Amplify your impact where it matters most — building exceptional apps.

Leave the infrastructure headaches to us, while you focus on pushing boundaries, realizing your vision, and making a lasting impression on your users.

Get Started

Top comments (0)

ACI image

ACI.dev: Fully Open-source AI Agent Tool-Use Infra (Composio Alternative)

100% open-source tool-use platform (backend, dev portal, integration library, SDK/MCP) that connects your AI agents to 600+ tools with multi-tenant auth, granular permissions, and access through direct function calling or a unified MCP server.

Check out our GitHub!