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>
);
}
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} />
</>
);
}
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);
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>
);
}
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;
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>
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
.
Top comments (0)