Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

Redux isn’t dead

7 min read 2010

Redux Isn't Dead

Redux remains one of the most talked-about libraries in the frontend ecosystem, and for good reason. Its predictability allows us to write applications that behave consistently across platforms (client, native, and server), it’s easily debuggable, and it works with any UI layer.

But the conversation around Redux isn’t always positive; indeed, the Redux team released Redux Toolkit last year in response to many of the lingering criticisms against it. In spite of this — or maybe because of it — a number of new alternatives for state management have cropped up, yielding the conclusion that Redux may finally be on its way out.

You already know the position this post takes based on the title — no, Redux isn’t dead. In defense of that stance, we will cover the following:

We interviewed the primary Redux maintainer, Mark Erikson, on our new podcast.

Listen now.

Why use Redux?

In software development, where there is a problem, we can be sure someone will soon create a solution. The problem Redux was created to solve is state management.

In React, we could have a global state in a top-level component. This top-level component passes state down as props to the components (i.e., the child components) that require the data.

class App extends Component {
    constructor() {
        super()
        this.state = {
           friends: [
              { name:'Victor', age: 22 }, 
              { name:'Matt', age: 30 }, 
              { name:'Kate', age: 40 }
           ],
        }
    } 

    render() {
        const allFriends = this.state.friends.map(friend => friend.name)   
        return (
            <div className="tc">
                <h1 className="f1 pa">Friends</h1>
                <FriendList names ={allFriends}/>
            </div>
        );
    }   
}

In the above code sample, the child component FriendList receives the data allFriends as props. It could also still be passed down once again. (I know I shouldn’t be doing this in a class component in 2021, but you get the idea.)

The state in the top-level component can always be updated. A child component would update the global state by receiving a function from the top component to update.

class App extends Component {
    constructor() {
        super()
        this.state = {
           friends: [
              { name:'Victor', age: 22 }, 
              { name:'Matt', age: 30 }, 
              { name:'Kate', age: 40 }
           ],
          searchField: ''
        }
    } 

        onSearchChange = (event) => {
          this.setState({searchField: event.target.value}) 
        }  

    render() {
        const filteredFriends = this.state.friends.filter(friend => {
            return friend.name.toLowerCase().includes(this.state.searchField) 
        })

        return (
            <div className="tc">
                <h1 className="f1 pa">Friends</h1>
                <SearchBox searchChange={this.onSearchChange}/>
                <FriendList names ={filteredFriends}/>
            </div>
        );
    }   
}

In the above sample code, our searchField state is always updated using the onSearchChange function and passed down to the SearchBox component.

Here’s what our SearchBox looks like receiving the function for an update:

We made a custom demo for .
No really. Click here to check it out.

const SearchBox = ({searchChange}) => {
    return (
        <div> 
            <input
            className="br3 pa2 b bg-light-blue" 
            type="search" 
            placeholder="Search Robots"
            onChange={searchChange}
            />
        </div>
    );
}

All this prop drilling and dealing with component C getting data from component A becomes a hassle when your application gets larger.

There have been recent arguments that we do not strictly need Redux, but the truth isn’t so clear-cut. You don’t realize you need Redux until you build an application for which state management is not so straightforward.

Dan on Twitter: “I would like to amend this: don’t use Redux until you have problems with vanilla React. See https://t.co/RhzRGzEIe0 @CamJackson89 / Twitter”

I would like to amend this: don’t use Redux until you have problems with vanilla React. See https://t.co/RhzRGzEIe0 @CamJackson89

In the same vein, Pete Hunt, an ex-React team member, also said, “You’ll know when you need Flux. If you aren’t sure if you need it, you don’t need it.” If you are not sure if you need X, then you don’t need it.

So, to recap, we should use Redux if:

  • Our state will be updated frequently; here, Redux provides “a single source of truth”
  • Our application has a lot of state needed in many components
  • Our function/logic to update the state will be complicated

Just like every other tool, Redux has its downsides and trade-offs, too.

Alternatives to Redux

Before we dive into Redux alternatives, it must be clear that there are different architectures for state management. These patterns have all been used with React and other UI libraries to manage the state and its data flow.

The three patterns, neatly summed up in this tweet from Ilham Wahabi, are atomic, proxy, and flux.

Atomic

This architecture is similar to what React uses for the Context API and useState. This pattern allows you create your state as an atom and split them into smaller atoms, unlike the Redux store, which is a big container of all state.

Jotai is one example that uses this architecture. Let’s have a look a code sample.

import { atom } from 'jotai'

const countAtom = atom(0)
const friendAtom = atom('Matt')
const friendsAtom = atom(['Victor', 'Matt', 'Kate'])

The state above is split into smaller pieces and treated as an atom. Using a particular atom in your component will look like this:

import { useAtom } from 'jotai'

const Friend = () => {
  const [friend] = useAtom(friendAtom)
  return (
    <div>
      <p>{friend}</p>
    </div
  )
}

Recoil is another Redux alternative that uses the atomic architecture.

Proxy

This pattern uses the JavaScript Proxyobject to access the state. Proxy wraps an object and mutates the traditional behaviors of the object. Its main purpose is to create custom behavior or redefine the fundamental operators.

MobX and Valtio are two popular state management libraries that use this architecture. According to Valtio, it turns the object you pass into it a self-aware proxy.

import { proxy, useSnapshot } from 'valtio'

const bio = proxy({ age: 23, name: 'Victor' })  

Make changes to the state from anywhere in your application:

bio.friends = { name: 'Matt' }
bio.friends.amount = { number: 1 }

Or make a copy of the data from the proxy to be used for rendering:

function Bio() {
  const snap = useSnapshot(bio)
  return (
    <div>
      {snap.name}
      <button onClick={() => ++bio.friends.amount}>+1</button>
    </div>
  )
}

Valtio forces you to read from the snapshot and mutate from its source. The component will definitely re-render the part of the state that was mutated.

Flux

Flux architecture is used by Redux and Zustand. This pattern has several components that are linked together to handle state: the actions, dispatcher, stores, and controller views.

We’ll use Zustand as an example; it is not as large as Redux and has far less boilerplate.

import create from 'zustand'

const useStore = create(set => ({
  myName: 'Victor',
  age: 23,
  friends: 0,
  increaseFriends: () => set(state => ({ friends: state.friends + 1 })),
  loseAllFriends: () => set({ friends: 0 })
}))

Zustand regards our store as a hook. The set keyword combines the state into useStore.

Using the state in our component is just easy.

function BearCounter() {
  const bears = useStore(state => state.bears)
  return <h1>{bears} around here ...</h1>
}

function Bio() {
  const name = useStore(state => state.myName)
  const increaseFriends = useStore(state => state.increaseFriends)
  return (
    <h1>I am {name}</h1>
    <button onClick={increaseFriends}>Increase My Friends</button>
  )
}

Based on their architecture, the alternatives mentioned above — Jotai, Recoil, Zustand, and Valtio — have different methods of managing state, and in many ways, they arose as a response to the pattern Redux uses. Depending on your requirements, your application could benefit from using the atomic approach (Jotai or Recoil) or even the flux-like approach with Zustand rather than Redux thanks to its minimal API.

Common Redux misconceptions

Redux has too much unnecessary boilerplate

Redux has received a lot of flak from the JavaScript community, not only because of its “boilerplatey” code but because of its learning curve. Many devs miss the fact that Redux uses a design pattern that requires a lot of boilerplate code: the flux architecture, which makes use of its individual components for state management.

Flux uses the action component (method) to pass data to the dispatcher. The dispatcher gets the actions and helps to redistribute the property that holds the state to its callback. This property is what we know as the payload.

Then, the store acts as our state and logic container, which is linked to the callbacks. All these operations require a lot of boilerplate. Even those who bash Redux for the sheer amount of boilerplate have to admire this architecture.

Redux is overkill

Dan Abramov himself has made no secret of the fact that you probably don’t need Redux for your project. I would say you only need Redux when your application scales and becomes complex; a smaller app or a personal project could likely get by fine with the Context API.

Speaking of the Context API, it works well when you have to share global state data — no need to pass data as props all the time for each component. Indeed, sometimes this is enough, and a sophisticated external state management solution like Redux is overkill. We should be clear however, that Context is not a state management solution, but an easier way to take data to a nested component.

Likewise, some people have claimed that Redux is dead because React’s Hooks API is perfectly capable of handling state already, especially when used together with the Context API. That’s not totally false, but a lot of this backlash is a result of the stress of prop drilling. If you don’t want to have to drill props into components, then Redux should not be your choice.

My point is that much of the criticism against Redux is the result of misconceptions like these. Many devs use Redux poorly or use it when it isn’t necessary. It is best to understand your project before choosing Redux.

The future of Redux

In many ways, the future is now thanks to Redux Toolkit (RTK). This toolkit helps with the abundance of boilerplate code Redux offers by default, providing a simplified store setup, reducers, and actions. It also includes all the packages commonly used alongside Redux so we don’t have to install them all individually —packages like Reselect, Redux Thunk, Immer, and more.

Installing this toolkit is easy:

# In your already existing React application, run either of these commands

# npm
npm install @reduxjs/toolkit

# Yarn
yarn add @reduxjs/toolkit

The APIs that RTK provides are createStore(), createReducer(), createAction(), and createSlice(), which help to simplify the Redux boilerplate code. This one improvement to the Redux development.

createSlice() makes your reducers and actions for you and connects them as well. React Redux also has the useDispatch and useSelector APIs now, which means you can connect to the dispatch actions and store without having to do use a HOC.

In my own opinion, Redux is never going anywhere in the coming years because it is such a great fit with React. There is no reliance or dependency on either of these libraries; React will be used on the view side of your application, while Redux handles the state.

Hooks and the Context still don’t provide as much power as Redux in terms of state management. In fact, it has been clearly explained that they are not a true state management solution. They’re just state providers — you still have to provide the logic in the components.

Redux employs a pub/sub architecture: your component is subscribed to state changes, and the component can also publish state changes using the dispatch. You might try employing the Context API in this scenario, but you’d likely end up having to use Redux in the end. There are firsthand stories out there about how using Context for state management can kill application performance.

The point is that Redux gives you more than state management. From the design pattern to the easy maintenance and scalability as the application grows, you’re able to decouple your state management logic from your UI layer. Redux is still useful, still has a future, and is most definitely not dead.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Victor Jonah I am a Software Developer with over three years of experience working with JavaScript and its frameworks. I currently work as a remote software developer for a tech agency.

2 Replies to “Redux isn’t dead”

  1. Hi, I’m the primary Redux maintainer. I’d like to point out that I’ve covered this topic _repeatedly_ over the last few years 🙂 This post is definitely on the right track (and especially the mentions of Redux Toolkit!), but it’s worth pointing to the many resources I’ve written on these topics already for additional info. Some of the key posts I’ve written around this are:

    Redux – Not Dead Yet!: obviously the same thesis as this post, but with an emphasis on how Redux relates to other tools
    When (and when not) to Reach for Redux: A podcast transcript excerpt where I discuss some of the purposes and use cases for Redux and how tools like React Query and Apollo overlap with those scenarios
    A vidcast talk where I cover current Redux usage stats
    Why React Context is Not a “State Management” Tool (and Why It Doesn’t Replace Redux): an extensive post where I cover the differences in capabilities and use cases for Context, useReducer, and Redux, and when it makes sense to use either of them
    Redux Toolkit 1.0: covers the intent and purpose behind the creation of Redux Toolkit and what problems it’s trying to solve

Leave a Reply