Are you still managing React state with plain Redux? Consider the Benefits of RTK.

Redux Toolkit is a must-have replacement for React state management.

In 2015, Dan Abramov blessed the world with his magnum opus of application state management tools: Redux. Described as a predictable, centralized, debuggable, and flexible state container, it became the de facto method of managing state for React applications.

But 2015 was a long time ago. Since then, new frameworks, add-ons, and updates – nearly 15,000 in npm – have been piled onto redux. There is little reason to continue to use plain Redux since there is a better package available in Redux Toolkit.

What? Another new JavaScript package?

Yes, if you’re a web developer then you probably just finished learning another javascript package. But the new thing you’re about to learn is pretty awesome, and possibly, the mother of all invention. Why do I say this? Because new Redux packages have been invented to address the needs of the developers that use them. However, while the benefits of plain Redux for creating a consistent state are significant, the pain points are also present.

Pain point #1

Plain Redux makes you write a lot of code for something that feels like it should be simple.

A file for action constants, another file for actions, and still another file for reducers? And then maybe another file for thunks? If I want to add or modify an action or reducer, I need to update three or more files!

Pain point #2

Plain Redux is not turnkey

After running `npm install redux,` you must install the associated helper packages, extract and apply middleware, and pass those parameters to the store. Make sure they’re in the proper order! – then, add reducers to your store, associate actions with your reducers, create thunks to dispatch your actions, then add dispatch calls to your thunks from your components. There are several pieces to add to accompany this solution.

Per the Redux documentation, setting up a typical store can look like this (just to get started!)

import { applyMiddleware, createStore } from 'redux' 
import { composeWithDevTools } from 'redux-devtools-extension' 
import thunkMiddleware from 'redux-thunk' 
 
import monitorReducersEnhancer from './enhancers/monitorReducers' 
import loggerMiddleware from './middleware/logger' 
import rootReducer from './reducers' 
 
export default function configureStore(preloadedState) { 
  const middlewares = [loggerMiddleware, thunkMiddleware] 
  const middlewareEnhancer = applyMiddleware(...middlewares) 
 
  const enhancers = [middlewareEnhancer, monitorReducersEnhancer] 
  const composedEnhancers = composeWithDevTools(...enhancers) 
 
  const store = createStore(rootReducer, preloadedState, composedEnhancers) 
 
  if (process.env.NODE_ENV !== 'production' && module.hot) { 
    module.hot.accept('./reducers', () => store.replaceReducer(rootReducer)) 
  } 
 
  return store 
} 

Pain point #3

Redux relies on other packages to be useful

To be able to view the store, you must include redux-devtools-extension. To use the thunks to dispatch actions asynchronously, you must include redux-thunk. Redux is so unopinionated and flexible that its usefulness is almost entirely dependent on including other libraries.

These problems make it cumbersome to venture into Redux alone. Luckily for us, the very same team that wrote Redux also created a package to make these pain points all but disappear.

Redux Toolkit (RTK)

“Official” Toolkit Can Be Confusing

This is the “official” toolkit for Redux development. Even in the vanilla Redux documentation, the first paragraph under Getting Started is… “Redux Toolkit is our official recommended approach for writing Redux logic…” Searching the vanilla Redux docs for “Redux Toolkit” returns 134 references. There’s even an in-your-face call to use RTK in the Introduction left navigation:


For this reason I’ve Included these links:

Why use RTK?

The stated goal of RTK is to help simplify common use cases seen in Redux. Per the docs: Usage Guide

“The Redux core library is deliberately unopinionated. It lets you decide how to handle everything, like store set up, what your state contains, and how you want to build your reducers.

This is good in some cases because it gives you flexibility, but that flexibility isn’t always needed. Sometimes we want the simplest possible way to get started, with some good default behavior. Or, maybe you’re writing a larger application and finding yourself writing some similar code, and you’d like to cut down on how much of that code you have to write by hand.”

How does RTK addresses the pain points above?

Pain point #1: Redux makes you write a lot of code for something that feels like it should be simple.

RTK Solution

Use “slices” and declare your action constants, actions, and reducers all in the same object.

RTK introduces the slice pattern, which allows you to declare and initialize your action constants, actions, and reducers all in one place. The standard approach for writing Redux logic is using the createSlice function.

Suppose you wanted a simple store that contained a ” counter ” property that could be incremented, decremented, or reset.

 

This is how to write “counter” with vanilla Redux
// actions.js 
… 
const COUNTER_INCREMENT = 'counter/increment' 
const COUNTER_DECREMENT = 'counter/decrement' 
const COUNTER_RESET = 'counter/reset' 
… 

// counterActions.js 
const incrementAction = { 
  type: COUNTER_INCREMENT, 
} 
 
const decrementAction = { 
  type: COUNTER_DECREMENT, 
} 
 
const resetAction = { 
  type: COUNTER_RESET, 
} 

// reducer.js 
const initialState = { counter: 0 } 
 
function counterReducer(state = initialState, action) { 
  if (action.type === COUNTER_INCREMENT) { 
    return { ...state, counter: state.counter + 1 } 
  } else if (action.type === COUNTER_DECREMENT){ 
    return { ...state, counter: state.counter - 1 } 
  } else if (action.type === COUNTER_RESET){ 
    return { ...state, counter: initialState.counter } 
  } 
  return state 
} 
This is how to write “counter” with RTK createSlice
// counterSlice.js 
import { PayloadAction, createSlice } from '@reduxjs/toolkit' 
 
const initialState = { counter: 0 } 
 
const counterSlice = createSlice({ 
  name: 'counter', 
  initialState, 
  reducers: { 
    increment: (state) => { 
      state.counter++ 
    }, 
    decrement: (state) => { 
      state.counter-- 
    }, 
    reset: (state) => { 
      state.counter = initialState.counter 
    }, 
  }, 
}) 

One file, one object, fewer lines of code, and a lot more readability!

You may have noticed that we’re updating the state directly in the slice instead of returning a new state object. We can do this and still follow Redux’s immutability rules because RTK is built using Immer, which creates a draft of the state you mutate directly and is then used by Immer to return a new state without mutating the original state.

Pain point #2: Redux is not turnkey

RTK Solution

RTK lets you set up a simple store in a just a few lines

RTK dramatically simplifies the setup of a common store with the configureStore function, which takes an object of named properties as its single parameter instead of multiple subsequent parameters. You can also optionally provide arrays of middleware and enhancers with applyMiddleware and compose being called for you under the hood automatically. Redux DevTools is enabled automatically as well.

 

This makes setting up a store this simple…
import { configureStore } from '@reduxjs/toolkit' 
import rootReducer from './reducers' 
 
const store = configureStore({ reducer: rootReducer }) 
 
export default store 
 

Pain point #3: Redux relies on other packages to be useful

RTK Solution

RTK includes commonly used packages by default.

As previously stated, Redux DevTools is included with RTK; there’s no need to add redux-devtools-extension. (Link)

configureStore adds some middleware by default, each with a specific goal:

    • redux-thunk is the most commonly used middleware for working with both synchronous and async logic outside of components
    • In development, middleware checks for common mistakes like mutating the state or using non-serializable values.

Conclusion

Will another new JavaScript package replace RTK? And Redux? And React? Almost certainly, but have no fear! As web developers, we’re called upon to use the latest and greatest proven packages that give our users and us the best experience we can provide. And for the time being, RTK seems to be the mightiest vehicle to carry us into our React state management future.

About Intertech

Intertech is a Twin Cities-based proven software development leader with a national presence. Specializing in a range of application services, including custom software development, legacy software modernization, business process automation, WebAssembly, Microservices, cloud application development, and complete system integration, Intertech blends expertise with the leadership and soft-skills that allow clients to focus on their day-to-day while we deliver the project successfully. In doing so, Intertech teams combine proven full-stack, Agile-experienced consultants with Delivery Management, User Experience, software development, and Quality Assurance and testing expertise. Our industry experience, from financial services to healthcare to manufacturing and agriculture, is extensive. In addition, our Education Division, designed to support our consulting customers, has helped Fortune 500 corporations and government agencies pivot to new technologies seamlessly. And our MomentumWorks team gives clients an offshore alternative without the risk, providing a proven, lower-cost option for support.