Skip to content

Redux Toolkit 2.0 release

Redux Toolkit 2.0 release

Intro

Redux Toolkit

On December 4, 2023, Mark Erikson announced that Redux Toolkit 2.0 has been released!

Mark Erikson tweet announcing RTK 2.0

This change is considered a major version of the library and comes with breaking changes because, as the core team declared, it has been 4+ years since they released Redux tool kit, and they needed to clean up the code and standardize the way Redux apps are written. One of these changes is you no longer need to import the core redux library, RTK is a wrapper of it. In this article, we are going to focus on the main breaking changes and new features in RTK 2.0

Some general notes on the change

  • Standalone getDefaultMiddleware and getType removed
  • The package definitions now include an exports field to specify which artifacts to load, with a modern ESM build
  • UMD has been dropped
  • Typescript rewrite

createSlice and createReducer

One of the major changes is object syntax for createSlice.extraReducers and createReducer removed. In RTK 2.0, Redux team has opted to remove the 'object' form for createReducer and createSlice.extraReducers, as the 'builder callback' form offers greater flexibility and is more TypeScript-friendly, making it the preferred choice for both APIs

So an example like this:

// Creating an action creator function called 'itemAdded'
const itemAdded = createAction('items/itemAdded');

// Using 'createReducer' function to define reducers
createReducer(initialState, {
  [todoAdded]: (state, action) => {
  },
});

// Using 'createSlice' function to define a slice of state and its reducers
createSlice({
  name, // Name of the slice (assumed to be defined elsewhere)
  initialState, // Initial state of the slice (assumed to be defined elsewhere)
  reducers: {},
  // Defining extra reducers for actions outside of this slice
  extraReducers: {
    // Defining a reducer for the 'itemAdded' action
    [itemAdded]: (state, action) => {},
  },
});

Should be like this:

// Using 'createReducer' function to define reducers
createReducer(initialState, (builder) => {
  // Using 'addCase' method of the builder to add a case reducer for the 'itemAdded' action
  builder.addCase(itemAdded, (state, action) => {});
});

// Using 'createSlice' function to define a slice of state and its reducers
createSlice({
  name, // Name of the slice (assumed to be defined elsewhere)
  initialState, // Initial state of the slice (assumed to be defined elsewhere)
  reducers: {},
  // Defining extra reducers for actions outside of this slice
  extraReducers: (builder) => {
    // Using 'addCase' method of the builder to add a case reducer for the 'itemAdded' action
    builder.addCase(itemAdded, (state, action) => {});
  },
});

Middlewares

Now the configureStore.middleware must be a callback. That’s because before to add a middleware to the Redux store, you had to add it to the array of configureStore.middleware, but this is turning off the default middleware. Now it’s a callback function that should return an array with middlewares, the default middleware is being passed in the parameters of the callback function so the developer can include it or not in the middleware array like this:

const store = configureStore({
  reducer,
  middleware: (getDefaultMiddleware) => {

    // This will not run the default Middleware and run myCustomMiddleware instead

    return [myCustomMiddleware]
  },
})

Enhancers

Store enhancers are a formal mechanism for adding capabilities to Redux itself like adding some additional capabilities to the store. It could change how reducers process data, or how dispatch works. Most people will never need to write one. But similar to the middlewares, enhancers also must be a callback function that receives getDefaultEnhancers and should return enhancers back.

const store = configureStore({
  reducer,
  enhancers: (getDefaultEnhancers) => {
    return getDefaultEnhancers({
      autoBatch: { type: 'tick' },
    }).concat(myEnhancer)
  },
})

autoBatchEnhancer

In version 1.9.0, the Redux team introduced a new autoBatchEnhancer that, when multiple "low-priority" actions are dispatched consecutively. This enhancement aims to optimize performance by reducing the impact of UI updates, typically the most resource-intensive part of the update process. While RTK Query automatically marks most of its internal actions as "low-pri" users need to add the autoBatchEnhancer to the store for this feature to take effect. To simplify this process, configureStore has been updated to include the autoBatchEnhancer in the store setup by default, allowing users to benefit from improved performance without manual store configuration adjustments.

AnyAction and UnknownAction

The Redux TS types have historically exported an AnyAction type that lacks precise type safety, allowing for loose typology like console.log(action.whatever). However, to promote safer typing practices, they've introduced UnknownAction, which treats all fields beyond action.type as unknown, nudging users towards creating type guards with assertions for better type safety when accessing action objects. UnknownAction is now the default action object type in Redux, while AnyAction remains available but deprecated.

RTK Query behavior

They've addressed issues with RTK Query, such as problems with dispatch(endpoint.initiate(arg, {subscription: false})) and incorrect resolution timing for triggered lazy queries, by reworking RTKQ to consistently track cache entries. Additionally, they've introduced internal logic to delay tag invalidation for consecutive mutations, controlled by the new invalidationBehavior flag on createApi, with the default being 'delayed'. In RTK 1.9, the subscription status has been optimized syncing to the Redux state for performance, primarily for display in the Redux DevTools "RTK Query" panel.

Conclusion

This version is a major version of Redux Toolkit and it has a lot of breaking changes but what is important its source code has been cleaned and rewritten in TS will improve the developer experience for sure and on the final user experience as well, We discussed here only the headlines and the most used features but of course you can find all of the changes on The official Redux Github Releases page