Moving away from Redux to SWR + Zustand

Riya Lohia
7 min readJun 6, 2023

--

In this blog, we will cover the reasons behind abandoning Redux in favor of SWR and Zustand for data and state management. Before moving on, let us first talk about the significance of data and state management.

Data management is one of the most critical components of software engineering. Although the first thought when someone says data management is of servers and databases, data management on the frontend is equally crucial. If we handle the data correctly, we will be able to reduce the number of API calls. Nowadays, there are numerous libraries that help us in supporting state management in React.

The Need for State Management

In React applications, we usually maintain the data in components. As the number of features increases, the number of components also increases and that makes data management difficult. To understand this better, let us have a look at the following diagram.

We have a component tree in which each layer has one more component than the previous layer, starting with a single parent root node. We fetch data from our API and save it in the state of component 7. Let’s say that component 8 which is an indirect sibling of component 7 wants to access that data. One solution would be to lift the state to component 2 and pass it down to both components 7 & 8 but that is neither an optimum solution nor a scalable one. The better solution would be to have some kind of global state that all the components irrespective of hierarchy can access, as shown in the second diagram. This is the basic idea behind state management, we can have single or multiple stores in our application

Most companies have multiple teams working on multiple isolated components but often, there is data overlap. Along with that, some data like logged-in user information is required on almost all of the applications owned and managed by different teams. So to avoid repetition of the same API calls for all components separately, it is wise to use a global store or multiple micro stores on the frontend to store such (re)usable data, across the application. So advantages of having central state management are:

  • We can access the data in every component. This adds to the speed of application development.
  • We avoid multiple API calls. This reduces the load on backend servers.

State Management Tool

There are multiple state management tools, making it easier to maintain states. The most commonly used library is Redux.

Redux

Redux is a State Management Tool that helps the components in our React App communicate with each other. Redux provides a single centralized place to contain the global state in our application and to follow specific patterns when updating that state. Each component in the application can access the central store to access the state.

Redux comprises three parts: Store, Action, and Reducer. Action help in making all our API requests or user interactions. These actions are sent to the reducer. Reducers are pure functions that take the current state of an application, perform an action, and return a new state. These states are stored as objects. All of these things happen inside the Redux store, which holds the state of the entire application. Then, the component gets a new state value and it re-renders the UI.

Why Redux is not the best option?

Redux Size

The Redux store in large web applications can grow significantly and it hinders the application rendering for all users and all pages regardless of whether the page uses the store or not. This is one area that can be optimized to speed up the website.

Redux requires lots of boilerplate code

To make a simple API call or any simple action and store it in the global store, developers need to create ACTIONS, SELECTOR and REDUCER where the selector is used for fetching data from the store. This process is time-consuming and complex.

Redux is not a Cache

The problem most developers are getting into when using Redux was that we treat it as a cache for our backend APIs. We fetch data, add it to our redux store, and re-fetch it periodically to make sure it’s up to date. We were making Redux a catch-all solution to problems. This is, however, not what Redux was meant for. Redux is supposed to store data accessed from multiple sources and is not limited to backend APIs.

Approaches Taken to Move Away from Redux

In order to solve the above problems, we can move common information needed from Redux (like User Auth data), and abstracted it to a secondary state manager like Zustand. We can use SWR + Zustand for our page’s state management as it works really well, abstracts use cases to hooks, and provides all the functionality provided by Redux along with a smaller footprint, scoped to just the page.

Why Zustand over Redux?

Zustand is an open-source lightweight state management library. It has currently already gained a lot of attraction. It is one of the lightest state management libraries available right now, with just 1.5 KB in size. It is known for its simplicity. Global State in zustand can be created with just four lines of code.

For example, a global counter state in zustand can be created with just the following lines:

export const useStore = create((set) => ({
counter: 0,
increment: () => set((state) => ({ counter: state.counter + 1 })),
decrement: () => set((state) => ({ counter: state.counter - 1 })),
}));

Wherever the above hook is injected and the state is used, the component will re-render when the state changes, making it a fully functional global state with these small lines of code.

Use of Zustand

  1. Less Boilerplate and Design
    One major drawback of using Redux is the amount of code we have to write to have a global state while in zustand, it can be done with just four lines of code. This can save us a lot of time.
  2. Zustand doesn’t wrap your app in context providers
    Redux needs to be wrapped with a provider component that injects state/data into all of its child components. With Zustand, we can just create the store and inject it wherever we want.
  3. Size
    Redux needs to be wrapped with a provider component that injects state/data into all of its child components. With Zustand, we can just create the store and inject it wherever we want.
  4. Contextful nature of Zustand Stores
    Actions and constants created for Redux are often kept in files separate from their associated reducers and can be used across multiple Reducers. With Zustand, everything linked to one context/use-case is always a part of the store and is present in the same file.
  5. Zustand can inform components transiently without causing a render
    It allows adding subscriber functions to enable components to bind to the state without forcing re-rendering on updates.

Why SWR over Fetch API?

SWR stands for stale-while-revalidate. It’s a React Hooks library used for data fetching. SWR simplifies things and increases the user experience of React app. SWR works in three main steps:

  1. Returns the data from the cache (stale data)
  2. Sends the fetch request (revalidate)
  3. Returns the up-to-date data.

SWR under the hood uses the Fetch API to request data from the server. It is kind of a layer built on top of it. It has some nice features such as caching, pagination, scroll position recovery, smart error retry, etc. It is a big advantage because having such features helps to make our React Apps fast and user-friendly and reduces the size of our code.

Use of SWR

  1. Built-in Cache
    Using SWR’s strategy, the user sees the cached (stale) data first and API request results are automatically cached ensuring the UI will always be fast and reactive.
  2. Pagination
    One of the most useful features of SWR is that it supports pagination and infinite loading of data. and we don’t need to write our logic to create an infinite-loading UI.
  3. Scroll position recovery
    SWR helps in retaining the scroll position while navigating through pages.
  4. Auto Revalidation
    SWR ensures that the user sees the most up-to-date data. So, even with multiple tabs or windows, the data is always fresh and in sync when the window or tab is refocused.

Impact Observed

We at unacademy, are gradually removing the Redux store from all parts of our application, as well as stopping any new feature development from happening in Redux. But this is, however, time-consuming and resource-intensive.

A few improvements we noticed:

  • Page Size has decreased by ~500KB per visit.
  • Unused JavaScript has decreased by 70% since we started the charter.
  • The GZipped size of the common app chunk that loads for all pages has come down from ~400KB to ~190KB on our site.
  • The Stat Size for our common bundle has dropped from 5.71MB to 1.58MB

--

--