Upeksha Herath
2024-05-30
State Management in React
State management in React is both popular and essential. This is because passing data between components, organizing code, dynamically updating the UI, and handling side effects are vital for any software application, regardless of its scale. There's nothing to worry about if you're not familiar with these concepts because, in this blog, we'll explore step-by-step the state management methods and how to choose the best one for our applications.
What is state?
The state is any data that describes the current behavior of an application.
Keeping track of an application's state is not specific to React. Even if you use Angular, Vue, or any other component-based UI library or framework, keeping track of the current state is a must.
Ways to keep state in a React application
In a React application, we primarily manage state in two ways:
- UI State: This type of state results from user interactions with specific UI elements, such as alerts, authentication, and modals. This state vanishes with each browser refresh and is simple to retrieve and synchronous. UI state can be categorized into two types:
- I. Local State: Data specific to a particular component and its behavior.
- II. Global State: Data that affects the entire application or several components and their behavior.
- Server State or Cache State: This refers to data that originates from the server and is stored on the client side for performance optimization purposes. It is not strictly considered state in the traditional sense, but rather cached data fetched from the server. Managing server state presents new challenges, such as caching, deduping requests, incremental fetching, mutations, handling outdated requests, and data synchronization.
In this blog post, let's discuss local and global states. We'll cover server state in a separate blog post later.
How to maintain the state locally?
React itself provides some ways to maintain the state in a React functional component. In function-based components, we can use the useState hook to maintain the local state. This state is only accessible inside that specific component. Here is a simple example which explains the most commonly used hook in React — useState.
Alright, now that we understand how to maintain local state, let's consider a situation where we need to pass this local state from one component to a child component. To do this, we use props, which allows us to easily pass data to the child component.
If we explain this in a much simpler way,
Code snippet: Parent to child data passing using props
But imagine you have to pass data to a grandchild. This means you'd have to pass data through two layers, from one component to another twice. Isn’t it annoying? This tedious process is known as prop drilling in React.
Image: Parent-to-grandchild data passing using props
To overcome this problem, we have to maintain a global state and pass data directly to the child components. So there is no need to pass data as props.
If you need to implement the third approach, which means to maintain a global state, then how can we do that?
How do we maintain the state globally?
To work with the state globally there are many options. Out of that;
- Context API — Built-in React feature for sharing data across components.
- Redux — Predictable state container for JavaScript applications, particularly useful for managing complex application states in React projects.
- Redux toolkit — Redux Toolkit (RTK) is an official add-on library for Redux that simplifies common tasks and reduces boilerplate code.
- Zustand — A small, fast, and scalable bearbones state management solution with a minimalistic approach.
- MobX — Simple, scalable state management.
- Jotai — Minimalistic state management library with an emphasis on simplicity and performance.
Are there popular choices out there? Yes, there are many libraries that can be used to maintain the global state of a React application.
So how do we choose the right library when there are so many options?
-
Technical Requirements: Consider your application's technical requirements. For example, if you have a legacy React application with class components, you won't be able to use Zustand because it relies on hooks, which aren't compatible with class components. This makes Zustand an unsuitable choice for such projects.
-
Development Team Expertise: Take into account the expertise of your development team. If the entire team is well-versed in a specific state management solution, like the React toolkit, and prefers to use it, there's little reason to choose a different option unless there are significant technical incompatibilities.
-
Client Requirements: Client preferences are crucial. We develop software to meet our clients' needs, and their preferences must be considered when selecting a state management solution. Sometimes, projects are already using a particular state management solution, and we need to continue with what's already in place.
These are just a few considerations, and there are many more factors to keep in mind when choosing a state management approach. Sometimes, it's necessary to use a more complex, feature-rich solution to accommodate the future needs of the application. Other times, it's best to keep the codebase as minimal and simple as possible.
As mentioned at the beginning of this blog, it's crucial to make the right choice based on the specific requirements. Otherwise, you might end up facing unnecessary complexities due to inappropriate state management.
One key thing to remember:
Until you truly need a global state management approach, avoid using a global state management library.
Now that you have a good understanding of React state management, stay tuned for the next blog post. We'll dive deep into state management with the Redux toolkit using a practical approach. See you in the next blog!
Share on: