The official, opinionated, batteries-included toolset for efficient Redux development

Overview

Redux Toolkit

build status npm version npm downloads

The official, opinionated, batteries-included toolset for efficient Redux development

(Formerly known as "Redux Starter Kit")

Installation

Using Create React App

The recommended way to start new apps with React and Redux Toolkit is by using the official Redux+JS template for Create React App, which takes advantage of React Redux's integration with React components.

npx create-react-app my-app --template redux

An Existing App

Redux Toolkit is available as a package on NPM for use with a module bundler or in a Node application:

# NPM
npm install @reduxjs/toolkit

# Yarn
yarn add @reduxjs/toolkit

It is also available as a precompiled UMD package that defines a window.RTK global variable. The UMD package can be used as a <script> tag directly.

Purpose

The Redux Toolkit package is intended to be the standard way to write Redux logic. It was originally created to help address three common concerns about Redux:

  • "Configuring a Redux store is too complicated"
  • "I have to add a lot of packages to get Redux to do anything useful"
  • "Redux requires too much boilerplate code"

We can't solve every use case, but in the spirit of create-react-app and apollo-boost, we can try to provide some tools that abstract over the setup process and handle the most common use cases, as well as include some useful utilities that will let the user simplify their application code.

Because of that, this package is deliberately limited in scope. It does not address concepts like "reusable encapsulated Redux modules", data caching, folder or file structures, managing entity relationships in the store, and so on.

What's Included

Redux Toolkit includes these APIs:

  • configureStore(): wraps createStore to provide simplified configuration options and good defaults. It can automatically combine your slice reducers, adds whatever Redux middleware you supply, includes redux-thunk by default, and enables use of the Redux DevTools Extension.
  • createReducer(): that lets you supply a lookup table of action types to case reducer functions, rather than writing switch statements. In addition, it automatically uses the immer library to let you write simpler immutable updates with normal mutative code, like state.todos[3].completed = true.
  • createAction(): generates an action creator function for the given action type string. The function itself has toString() defined, so that it can be used in place of the type constant.
  • createSlice(): accepts an object of reducer functions, a slice name, and an initial state value, and automatically generates a slice reducer with corresponding action creators and action types.
  • createAsyncThunk: accepts an action type string and a function that returns a promise, and generates a thunk that dispatches pending/resolved/rejected action types based on that promise
  • createEntityAdapter: generates a set of reusable reducers and selectors to manage normalized data in the store
  • The createSelector utility from the Reselect library, re-exported for ease of use.

Documentation

The Redux Toolkit docs are available at https://redux-toolkit.js.org.

Issues
  • Create Async Action

    Create Async Action

    redux-starter-kit includes redux-thunk but doesn't include an async version of createAction. I want to float the idea of a createAsyncAction function that uses thunks; I can create a pull request if all looks good.

    Here's a rough initial API proposal:

    // To be added:
    // (Inspired by the current implementation of `createAction`)
    function createAsyncAction(type, thunk) {
      const action = payload => thunk(payload);
      action.toString = () => type;
      return action;
    }
    
    // Usage example:
    const someAsyncAction = createAsyncAction("SOME_ASYNC_ACTION", payload => {
      return dispatch => {
        return setTimeout(() => {
          // One second later...
          dispatch(someAsyncActionSuccess());
        }, 1000);
      };
    });
    
    const someAsyncActionSuccess = createAction("SOME_ASYNC_ACTION_SUCCESS");
    

    The only new proposal is at the top of that snippet, the function createAsyncAction. It takes two parameters: type (same as createAction) and thunk.

    What are everyone's thoughts?

    enhancement 
    opened by jamescmartinez 66
  • Consider rethinking tutorial sequence

    Consider rethinking tutorial sequence

    I've had a few folks say that they had trouble following the tutorials for different reasons:

    • The Advanced Tutorial is entirely written in TypeScript (example comment)
    • Both the Intermediate and Advanced tutorials show converting existing apps (Intermediate: plain Redux todos, Advanced: React-only Github Issues), rather than trying to build up an app with RTK specifically (example comment)

    I'd be open to the idea of redoing the tutorial sequence in some other way. Perhaps the existing pages could be semi-converted into "Usage Guides" of some kind: Intermediate -> "Migrating Existing Redux Apps", and Advanced -> some combo of "Adding Redux to a React App" and "TypeScript Example"?

    But, that means we'd need to rethink what the tutorials should cover, and rebuild them from scratch.

    I don't have time to do this myself right now, since I'm focused on the Redux core docs rewrite, but if someone else wanted to tackle this, I could offer guidance.

    docs 
    opened by markerikson 63
  • chore(build): move tsdx to esbuild

    chore(build): move tsdx to esbuild

    just try what esbuild cann't be done for author libraries

    opened by hardfist 57
  • Question: How to use this with redux-persist?

    Question: How to use this with redux-persist?

    I've been experimenting with getting redux-persist to integrate with my current project that's using react-starter-kit but I'm already hitting some walls and obscure errors.

    First issue is a middleware that doesn't seem to know how to handle the register call for the persist middleware (which is caused by serializable-state-invariant-middleware).

    Second issue is that PersistGate never renders, I can only assume this is because rehydrate is never called? I'm not really sure what's going on there, it's probably by own fault.

    If this isn't the place to ask I'm sorry, but using redux-persist seems like a very common use case.

    Update 1:

    I solved the serializable-state-invariant-middleware issue by simply adding thunk myself. (Note it needs to be manually installed!)

    Here's my store.ts:

    import logger from "redux-logger";
    import { configureStore } from "redux-starter-kit";
    import thunk from "redux-thunk";
    import rootReducer from "./reducers";
    
    const store = configureStore({
        reducer: rootReducer,
        middleware: [thunk, logger],
    });
    
    export default store;
    
    opened by SeedyROM 46
  • Consider using packages from  redux-utilities

    Consider using packages from redux-utilities

    The redux-utilities org has some pretty popular packages, it might make sense to depend on them partially. I haven't really used them that much so please voice your opinions.

    redux-actions

    This seems like a cool abstraction to handling actions, similar to the one we already have. Though if it requires FSAs it's probably not a great idea unless we can get them to patch it upstream to support plain actions.

    reduce-reducers

    This is a handy way to compose reducers together. I don't think we need it yet but it could help us write more complex high order reducers in the future.

    redux-promise

    This is one of the more popular async packages along with thunk and saga. I'm fine with redux-thunk, but could there be an advantage to switching to promises or supporting both thunks and promises? Can the thunk package alone support promises and completely replace the need to use redux-promise? I think that's an especially important thing to consider since many async HTTP request libraries use promises now.

    discussion 
    opened by nickmccurdy 42
  • yet another attempt at actionListenerMiddleware

    yet another attempt at actionListenerMiddleware

    Reference: #237, #432, #272 .

    So this is just the middleware and a few tests for it, I have not yet thought about how to usefully combine that into createDefaultMiddleware or even configureStore.

    Let's discuss the middleware itself for now and take a look at that later.

    The tests should showcase all functionality:

    • subscribing via method on the middleware
    • unsubscribing via method on the middleware
    • unsubscribing via returned callback from subscribing
    • subscribing via action
    • unsubscribing via action
    • unsubscribing via callback returned from dispatch

    Also, I've added the following options to each individual subscription (taken some extra inspiration from https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener):

    interface ActionListenerOptions<
      A extends AnyAction,
      S,
      _ extends Dispatch<AnyAction>
    > {
      /**
       * Indicates that the listener should be removed after if has run once.
       */
      once?: boolean
      /**
       * If set to true, the action will not be forwarded to
       * * listeners that were registered after this listener
       * * middlewares later in the middleware chain
       * * reducers
       * If this listener is skipped due to `options.condition`, this has no effect.
       */
      preventPropagation?: boolean
      /**
       * A function that determines if the listener should run, depending on the action and probably the state.
       */
      condition?(action: A, getState: () => S): boolean
    }
    

    So, let's discuss this :)

    opened by phryneas 38
  • add prepareAction option to createAction

    add prepareAction option to createAction

    This is a rough WIP for the feature requested in #148. Essentially, it allows to pass a prepare function with the signature (originalPayload: OriginalPayload) => {payload: Payload; meta? : Meta} to modify the Payload and potentially add a Meta to the created action. You can see examples of use in the type tests I added.

    This is working, but needs tuning around the types - but before that I would like some feedback if I'm going in the right direction with this.

    @markerikson @tanhauhau what do you think?

    opened by phryneas 38
  • [Feature] CRUD API Wrapper Implementation

    [Feature] CRUD API Wrapper Implementation

    I've been working on a fresh new project and this gave me the benefit of being able to not only use redux-toolkit, but also the freedom to write a "builder" for our multiple CRUD endpoints.

    After speaking with @markerikson , it became clear this might be something that's useful to a growing number of people. The basics of this is that the API endpoints we have are all similar in structure, and since CRUD operations usually have the same shape, I quickly ended up with a lot of duplicated code for each endpoint, where the only difference was the endpoint name.

    So I made a function that creates all of the thunks using createAsyncThunk and the customReducer entries to make them work. This is then returned and used in configureStore or in the various components that require the data.

    It's a little verbose as one might expect, but it works:

    import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
    
    export default ({
        baseUrl,
        name,
    }) => {
        const fetchById = createAsyncThunk(
            `${name}/fetchByIdStatus`,
            id => fetch(`${baseUrl}/${id}`).then(r => r.json()),
        );
    
        const fetchAll = createAsyncThunk(
            `${name}/fetchAllStatus`,
            () =>  fetch(`${baseUrl}/`).then(r => r.json()),
        );
    
        const updateById = createAsyncThunk(
            `${name}/updateByIdStatus`,
            async ({id, data}) => {
                await fetch(`${baseUrl}/${id}`, {
                    method: "UPDATE",
                    headers: {
                        'Content-Type': 'application/json',
                    },
                    body: JSON.stringify(data),
                }).then(r => r.json());
                return data;
            },
        );
    
        const deleteById = createAsyncThunk(
            `${name}/deleteByIdStatus`,
            id =>  fetch(`${baseUrl}/${id}`, {
                method: 'DELETE',
            }).then(r => r.json()).then(() => id),
        );
    
        const createNew = createAsyncThunk(
            `${name}/createNewStatus`,
            data => fetch(`${baseUrl}`, {
                method: 'PUT',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(data),
            }),
        );
    
        const slice = createSlice({
            name,
            initialState: { entities: {}, loading: 'idle'},
            reducers: {},
            extraReducers: {
                [fetchById.fulfilled]: (state, action) => {
                    state.entities[action.payload.id] = action.payload;
                },
                [fetchById.rejected]: (state, action) => {
                    state.entities[action.payload.id] = action.payload;
                },
                [updateById.fulfilled]: (state, action) => {
                    state.entities[action.payload.id] = action.payload;
                },
                [deleteById.fulfilled]: (state, action) => {
                    delete state.entities[action.payload.id];
                    return state;
                },
                [createNew.fulfilled]: (state, action) => {
                    state.entities[action.payload.id] = action.payload;
                },
                [fetchAll.fulfilled]: (state, action) => {
                    state.entities = {
                        ...state.entities,
                        ...action.payload,
                    };
                },
            },
        });
    
        return {
            reducer: slice.reducer,
            fetchById,
            fetchAll,
            updateById,
            deleteById,
            createNew,
        };
    };
    

    This is called simply by providing the baseUrl and the name (in our case the could be different so that's why we had to split those 2 arguments):

    export const cascades = builder({
        baseUrl: `${baseUrl}/cascade-blocks`,
        name: 'cascades',
    });
    
    export const groups = builder({
        baseUrl: `${baseUrl}/groups`,
        name: 'groups',
    });
    

    And then I imported those into our configureStore, combining them as a root reducer:

    import { cascades, groups } from './slices';
    const rootReducer = combineReducers( {
      cascades: cascades.reducer,
      groups: groups.reducer,
    } );
    
    export default store = configureStore({ reducer: rootReducer });
    

    The only thing missing from the above is my next step, which is to provide some selector functions that can getById, getAll, getIDs, and other useful related things.

    After adding the selectors I'll consider this to be a fairly self-contained, re-usable module that I'm sure we'll start using internally. Hopefully, it can be of service for Redux-Toolkit also!

    opened by eslachance 35
  • Discussion: Roadmap to 1.0

    Discussion: Roadmap to 1.0

    I'd been thinking about putting up a discussion issue like this already, and someone asked about it today, so figure I might as well.

    I deliberately started out at 0.1.0 to give us room to fiddle with the API before reaching stability. The "convert to TS" release put us at 0.4.0. So, what do we feel would be needed to reach a stable 1.0 status?

    Here's my rough thoughts on further changes I'm considering:

    • Selectors
      • [x] I'm considering dropping Selectorator, re-exporting createSelector from Reselect, ~~adding a dependency on Re-reselect, and re-exporting its createCachedSelector~~
      • ~~We might want to have a tiny wrapper around those that only accepts the array form of input selectors, not the arbitrary function arguments form~~ Looking like Reselect v5 may do this as a breaking change
    • createSlice
      • [x] I want to add the ability to handle other action types besides the ones generated for the provided reducers. Working on that now.
      • [x] Would like to consider the "customize payload callback" idea
      • [x] Change names of generated selectors (selectFoo instead of getFoo)?
      • [x] Returning a default selector that's just state => state is pointless. Why are we doing that? What should we do instead?
    • createAction
      • [x] add .type to the action creators in addition to .toString(). This helps with JS switch statements, as well as object lookup tables in TS.
    • Async requests
      • [ ] I'm open to some options for simplifying async request handling. Possibilities:
        • Generating "STARTED/SUCCESS/FAILURE" action types
        • Generating thunks that call a provided API function and dispatch those action types based on promise lifecycle
        • Pulling in redux-promise
    • More safety checks
      • ~~I'd like to see if I can make a middleware that checks for side effects that happen in a reducer (at least async requests and uses of randomness)~~ Skipping this idea
    • Other
      • [ ] Might as well add reduce-reducers to the toolkit
      • [ ] Should fix tree shaking
      • [x] Allow devTools to be more options beyond a boolean
      • [x] Review autodux to see if there's any other functionality we want to swipe
      • [ ] Consider adding a simple middleware that lets users define callbacks to run in response to specific actions (which thunks can't do)

    Not saying we have to have all of these, but those are the ideas floating around my head.

    Thoughts? Suggestions?

    opened by markerikson 34
  • chore(build): swap in tsdx

    chore(build): swap in tsdx

    There's still work that needs to happen as when I last worked on this there were still some important differences in the output around externals, but I figured I'd issue this PR so one can see the differences in a rough state.

    /cc @markerikson

    opened by RichiCoder1 33
  • invalid TypeScript Documentation for usage of transformResponse in rtk-query/enhanceEndpoints

    invalid TypeScript Documentation for usage of transformResponse in rtk-query/enhanceEndpoints

    In the docs, the example says:

    // An explicit type must be provided to the raw result that the query returns
    // when using `transformResponse`
    //                             v
    transformResponse: (rawResult: { result: { post: Post } }, meta) => {
    

    But this is not working, as doing so gives me this error (see sandbox example):

    Type '(rawResult: { foo: number[]; }, meta: {} | undefined) => number[]' is not assignable to type 'undefined'.ts(2322)
    
    opened by kasper-se 3
  • Pass baseQueryMeta into calculateProvidedBy

    Pass baseQueryMeta into calculateProvidedBy

    Patches the work done in https://github.com/reduxjs/redux-toolkit/pull/1910 by ensuring that we're exposing baseQueryMeta aka Request and Response objects... which matches the transformResponse behavior for consistency. I debated on doing a full use case example here, but it seemed like it wouldn't really provide any real value and would be better served in usage docs.

    Also note: I didn't update the docs for this as @bever1337 is working on those.

    opened by msutkowski 2
  • Document missing properties on `prepareHeaders` signature

    Document missing properties on `prepareHeaders` signature

    • Adds documentation for #1917.
    • Adds a test to assert that endpoint, type, forced are passed through to prepareHeaders
    opened by msutkowski 2
  • Handling errors at a macro level​ still catch error when first try was rejected and the second one is fulfilled

    Handling errors at a macro level​ still catch error when first try was rejected and the second one is fulfilled

    I'm trying to Handling errors at a macro level​ by using this example

    ` export const rtkQueryErrorLogger: Middleware = (api: MiddlewareAPI) => next => action => {

    if (isRejectedWithValue(action)) {
      toast.error(
        action?.payload?.data?.detail || action?.payload?.data?.title,
        {
          position: 'top-right',
          autoClose: 5000,
          hideProgressBar: false,
          closeOnClick: true,
          pauseOnHover: true,
          draggable: true,
          progress: undefined,
        },
      );
    } else if (isRejected(action)) {
      toast.error(action.error.message, {
        position: 'top-right',
        autoClose: 5000,
        hideProgressBar: false,
        closeOnClick: true,
        pauseOnHover: true,
        draggable: true,
        progress: undefined,
      });
    }
    
    return next(action);
    

    };

    `

    Every thing works find but when the first request is rejected the middleware catch the error but when the second request is fulfilled it catch the last error. I think errors is still cached.

    Is there a way to clear after each request ?

    opened by momolafrooo 0
  • How I remove authorization token from header

    How I remove authorization token from header

    95% of my APIs need token to receive data but I have also some APIs that I don t need token. How I remove the authorization header from my header query

    export const emptySplitApi = createApi({
        baseQuery: fetchBaseQuery({
            baseUrl: '/',
            prepareHeaders: (headers, { getState }) => {
                const token = getState().auth.token;
                if (token) headers.set('Authorization', 'Bearer ${token}');
                return headers
            }
        }),
        endpoints: () => ({})
    });
    
    export const authApi = emptySplitApi.injectEndpoints({
        endpoints: (builder) => ({
            load: builder.mutation({
                query: () =>
                ({
                    url: 'http://localhost:5000/api/user',
                    method: 'GET',
                })
            }),
            login: builder.mutation({
                query: credentials => ({
                    url: 'http://localhost:5000/api/login',
                    method: 'POST',
                    body: credentials,
                    headers:  {}  > Here I don t need token
                })
            }),
    
    opened by bylly1 2
  • TypeError: Cannot read properties of undefined (reading 'providesTags')

    TypeError: Cannot read properties of undefined (reading 'providesTags')

    I have a rather large enterprise app. It adds reducers and APIs dynamically:

    
    // create baseApi
    
    export const reduxApi = createApi({
      reducerPath: "reduxApi",
      baseQuery: fetchBaseQuery({ baseUrl: "/api/v1", fetchFn: mkiFetch }),
      endpoints: () => ({}),
    });
    
    // create store
    
     const middlewares = [thunk, reduxApi.middleware];
     createStore(
              rootPlugin.reducer,
              {}, 
              composeEnhancers(
                applyMiddleware(...middlewares)
              )
    );
    

    Next, it injects the endpoints:

    const sugApi = reduxApi.injectEndpoints({
      endpoints: (build) => ({
        listSUGs: build.query<SUG[], { networkId: string }>({
          query: ({ networkId }) => ({ url: `networks/${networkId}` }),
        }),
    });
    
    export const {
      useListSUGsQuery,
      useLazyListSUGsQuery,
    } = sugApi;
    

    However, when using useListSUGsQuery or useLazyListSUGsQuery, I get the above error.

    • The AJAX request seems to complete fine. (Network tab gives a 200 with expected data)
    • The redux slice records the pending query for useListSUGsQuery
    rtk-query.esm.js:695 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'providesTags')
        at calculateProvidedByThunk (rtk-query.esm.js:695:81)
        at eval (rtk-query.esm.js:876:36)
        at eval (redux-toolkit.esm.js:668:32)
        at produce (immer.esm.js:23:15962)
        at eval (redux-toolkit.esm.js:667:81)
        at Array.reduce (<anonymous>)
        at reducer (redux-toolkit.esm.js:646:29)
        at reducer (redux-toolkit.esm.js:721:20)
        at combination (redux.js:536:29)
        at reducer (rtk-query.esm.js:960:53)
    
    • redux: 3.7.2
    • redux-tookit: 1.7.1
    opened by frankandrobot 9
  • awaited dispatched queries are returning status: pending

    awaited dispatched queries are returning status: pending

    Hi I mentioned this in the discord channel and @phryneas was kind enough to talk me through how awaited dispatched rtkquery requests should be handled. He believed that what I was seeing shouldn't happen and asked me to create a code sandbox.

    I've now done that and its available here - https://codesandbox.io/s/peaceful-tereshkova-rvumb

    In the demo I'm using MSW to mock out all the data responses to clarify that it wasn't something funky with the actual API I consume.

    I'm using xState to model loading and deleting data from an API:

    The machine list.machine.ts starts off making a list request, then you can send 'DELETE_ITEM' event to ask the machine to transition to the delete state,at which it invokes the 'deleteListData' service, containing the rtkQuery api.endpoint call to delete a list item. At this point:

    • In the console's network tab the mock service worker has returned a new response with that item deleted
    • However, at the same time in the console you will see the awaited dispatch function return a status pending response, containing the stale data.
    • I'm guessing some time after this the store's data is finally updated with the request data, because if you delete the same item again the new list request still reports as pending but now its stale data contains the results from the previous request.

    This has me stumped! So any help greatly appreciated

    If I update the machine to delay between transitioning between the delete and list states then things work as expected:

    import { createModel } from "xstate/lib/model";
    import { ModelContextFrom, ModelEventsFrom } from "xstate/lib/model.types";
    
    import {
      Destination,
      ListDestinationsResponse
    } from "../service/destinations-api.generated";
    
    export const listModel = createModel(
      {
        data: [] as Destination[]
      },
      {
        events: {
          DELETE_ITEM: (id: string) => ({ id })
        }
      }
    );
    
    export const listMachine = listModel.createMachine({
      id: "list",
      initial: "loading",
      states: {
        loading: {
          invoke: {
            src: "fetchListData",
            onDone: {
              actions: assign({
                data: (
                  context,
                  event: DoneInvokeEvent<ListDestinationsResponse>
                ) => {
                  console.log("assign ", event.data.destinations);
                  return event.data.destinations ?? [];
                }
              }),
              target: "idle"
            },
            onError: {
              target: "error"
            }
          }
        },
        error: {},
        idle: {
          on: {
            DELETE_ITEM: {
              target: "delete"
            }
          }
        },
        pause: {
          after: {
            // after 0.1 second, transition to loading
            100: { target: "loading" }
          }
        },
        delete: {
          invoke: {
            src: "deleteListData",
            onDone: {
              target: "pause"
            }
          }
        }
      }
    });
    
    export type DestinationsListContext = ModelContextFrom<typeof listModel>;
    export type DestinationsListEvent = ModelEventsFrom<typeof listModel>;
    export type DestinationsListService = ActorRefFrom<typeof listMachine>;
    
    opened by pollen8 0
  • SyntaxError: Declaration or statement expected generating code from openapi spec

    SyntaxError: Declaration or statement expected generating code from openapi spec

    I have an openapi spec that, when run through codegen-openapi, produces this error:

    SyntaxError: Declaration or statement expected. (365:1)
      363 | });
      364 | export type Items5 = string;
    > 365 | export type 0 = {
          | ^
      366 |     offset?: number;
      367 |     limit?: number;
      368 | } & {
    

    The error shows it's trying to create a type named, "0". I attached a redacted copy of the openapi spec. openapi.zip .

    opened by dieseldjango 0
  • Cache invalidate based on headers

    Cache invalidate based on headers

    For RTK Query

    Currently the cache key takes only the query args into consideration for deciding validation of cache. We have an endpoint getPosts and in the headers of this GET request we are sending the JWT token of the user. The response is different based on whether the token is present or not. We use prepareHeaders to set the token in requests instead of sending it as arg in every request.

    baseQuery: fetchBaseQuery({
      baseUrl: apiConfig.baseUrl,
      prepareHeaders: (headers, { getState }) => {
        // By default, if we have a token in the store, let's use that for authenticated requests
        const token = (getState() as RootState).user.token
        if (token) {
          headers.set(Constants.AUTH_HEADER, token)
        }  
        return headers
      },
    

    But with current setup the getPosts will not refetch data from server if the token in Header changes. Is there any way / workaround to achieve this?

    • One solution is to send the token as query arg, but token needs to be sent every where the posts are required. Is there any way to minimize this?
    enhancement good first issue 
    opened by sriteja777 2
Releases(v1.7.1)
  • v1.7.1(Dec 16, 2021)

    This release fixes a types issue with RTK 1.7.0 and TS 4.5, as seen in #1829 .

    What's Changed

    • fix types for TS 4.5 by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1834

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.7.0...v1.7.1

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0(Dec 10, 2021)

    This feature release has a wide variety of API improvements:

    • updates RTK Query with support for SSR and rehydration
    • allows sharing mutation results across components
    • adds a new currentData field to query results
    • adds several new options for customizing endpoints and base queries
    • adds support for async condition options in createAsyncThunk
    • updates createSlice/createReducer to accept a "lazy state initializer" function
    • updates createSlice to avoid potential circular dependency issues by lazy-building its reducer
    • updates Reselect and Redux-Thunk to the latest versions with much-improved TS support and new selector customization options
    • Fixes a number of small code and types issues
    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    RTK Query

    RTK Query SSR and Rehydration Support

    RTK Query now has support for SSR scenarios, such as the getStaticProps/getServerSideProps APIs in Next.js. Queries can be executed on the server using the existing dispatch(someEndpoint.initiate()) thunks, and then collected using the new await Promise.all(api.getRunningOperationPromises()) method.

    API definitions can then provide an extractRehydrationInfo method that looks for a specific action type containing the fetched data, and return the data to initialize the API cache section of the store state.

    The related api.util.getRunningOperationPromise() API adds a building block that may enable future support for React Suspense as well, and we'd encourage users to experiment with this idea.

    Sharing Mutation Results Across Components

    Mutation hooks provide status of in-progress requests, but as originally designed that information was unique per-component - there was no way for another component to see that request status data. But, we had several requests to enable this use case.

    useMutation hooks now support a fixedCacheKey option that will store the result status in a common location, so multiple components can read the request status if needed.

    This does mean that the data cannot easily be cleaned up automatically, so the mutation status object now includes a reset() function that can be used to clear that data.

    Data Loading Updates

    Query results now include a currentData field, which contains the latest data cached from the server for the current query arg. Additionally, transformResponse now receives the query arg as a parameter. These can be used to add additional derivation logic in cases when a hooks query arg has changed to represent a different value and the existing data no longer conceptually makes sense to keep displaying.

    Data Serialization and Base Query Improvements

    RTK Query originally only did shallow checks for query arg fields to determine if values had changed. This caused issues with infinite loops depending on user input.

    The query hooks now use a "serialized stable value" hook internally to do more consistent comparisons of query args and eliminate those problems.

    Also, fetchBaseQuery now supports a paramsSerializer option that allows customization of query string generation from the provided arguments, which enables better interaction with some backend APIs.

    The BaseQueryApi and prepareheaders args now include fields for endpoint name, type to indicate if it's a query or mutation, and forced to indicate a re-fetch even if there was already a cache entry. These can be used to help determine headers like Cache-Control: no-cache.

    Other RTK Query Improvements

    API objects now have a selectInvalidatedBy function that accepts a root state object and an array of query tag objects, and returns a list of details on endpoints that would be invalidated. This can be used to help implement optimistic updates of paginated lists.

    Fixed an issue serializing a query arg of undefined. Related, an empty JSON body now is stored as null instead of undefined.

    There are now dev warnings for potential mistakes in endpoint setup, like a query function that does not return a data field.

    Lazy query trigger promises can now be unwrapped similar to mutations.

    Fixed a type error that led the endpoint return type to be erroneously used as a state key, which caused generated selectors to have an inferred state: never argument.

    Fixed transformResponse to correctly receive the originalArgs as its third parameter.

    api.util.resetApiState will now clear out cached values in useQuery hooks.

    The RetryOptions interface is now exported, which resolves a TS build error when using the hooks with TS declarations.

    RTK Core

    createSlice Lazy Reducers and Circular Dependencies

    For the last couple years we've specifically recommended using a "feature folder" structure with a single "slice" file of logic per feature, and createSlice makes that pattern really easy - no need to have separate folders and files for /actions and /constants any more.

    The one downside to the "slice file" pattern is in cases when slice A needs to import actions from slice B to respond to them, and slice B also needs to listen to slice A. This circular import then causes runtime errors, because one of the modules will not have finished initializing by the time the other executes the module body. That causes the exports to be undefined, and createSlice throws an error because you can't pass undefined to builder.addCase() in extraReducers. (Or, worse, there's no obvious error and things break later.)

    There are well-known patterns for breaking circular dependencies, typically requiring extracting shared logic into a separate file. For RTK, this usually means calling createAction separately, and importing those action creators into both slices.

    While this is a rarer problem, it's one that can happen in real usage, and it's also been a semi-frequently listed concern from users who didn't want to use RTK.

    We've updated createSlice to now lazily create its reducer function the first time you try to call it. That delay in instantiation should eliminate circular dependencies as a runtime error in createSlice.

    createAsyncThunk Improvements

    The condition option may now be async, which enables scenarios like checking if an existing operation is running and resolving the promise when the other instance is done.

    If an idGenerator function is provided, it will now be given the thunkArg value as a parameter, which enables generating custom IDs based on the request data.

    The createAsyncThunk types were updated to correctly handle type inference when using rejectWithValue().

    Other RTK Improvements

    createSlice and createReducer now accept a "lazy state initializer" function as the initialState argument. If provided, the initializer will be called to produce a new initial state value any time the reducer is given undefined as its state argument. This can be useful for cases like reading from localStorage, as well as testing.

    The isPlainObject util has been updated to match the implementation in other Redux libs.

    The UMD builds of RTK Query now attach as window.RTKQ instead of overwriting window.RTK.

    Fixed an issue with sourcemap loading due to an incorrect filename replacement.

    Dependency Updates

    We've updated our deps to the latest versions:

    • Reselect 4.1.x: Reselect has brand-new customization capabilities for selectors, including configuring cache sizes > 1 and the ability to run equality checks on selector results. It also now has completely rewritten TS types that do a much better job of inferring arguments and catch previously broken patterns.
    • Redux Thunk 2.4.0: The thunk middleware also has improved types, as well as an optional "global override" import to modify the type of Dispatch everywhere in the app

    We've also lowered RTK's peer dependency on React from ^16.14 to ^16.9, as we just need hooks to be available.

    Other Redux Development Work

    The Redux team has also been working on several other updates to the Redux family of libraries.

    React-Redux v8.0 Beta

    We've rewritten React-Redux to add compatibility with the upcoming React 18 release and converted its codebase to TypeScript. It still supports React 16.8+/17 via a /compat entry point. We'd appreciate further testing from the community so we can confirm it works as expected in real apps before final release. For details on the changes, see:

    • https://github.com/reduxjs/react-redux/releases/tag/v8.0.0-beta.0

    RTK "Action Listener Middleware" Alpha

    We have been working on a new "action listener middleware" that we hope to release in an upcoming version of RTK. It's designed to let users write code that runs in response to dispatched actions and state changes, including simple callbacks and moderately complex async workflows. The current design appears capable of handling many of the use cases that previously required use of the Redux-Saga or Redux-Observable middlewares, but with a smaller bundle size and simpler API.

    The listener middleware is still in alpha, but we'd really appreciate more users testing it out and giving us additional feedback to help us finalize the API and make sure it covers the right use cases.

    RTK Query CodeGen

    The RTK Query OpenAPI codegen tool has been rewritten with new options and improved output.

    What's Changed

    • fix "isLoading briefly flips back to true" #1519 by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1520
    • feat(createAsyncThunk): async condition by @thorn0 in https://github.com/reduxjs/redux-toolkit/pull/1496
    • add arg to transformResponse by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1521
    • add currentData property to hook results. by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1500
    • use useSerializedStableValue for value comparison by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1533
    • fix(useLazyQuery): added docs for preferCache option by @akashshyamdev in https://github.com/reduxjs/redux-toolkit/pull/1541
    • correctly handle console logs in tests by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1567
    • add reset method to useMutation hook by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1476
    • allow for "shared component results" using the useMutation hook by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1477
    • 🐛 Fix bug with useMutation shared results by @Shrugsy in https://github.com/reduxjs/redux-toolkit/pull/1616
    • pass the ThunkArg to the idGenerator function by @loursbourg in https://github.com/reduxjs/redux-toolkit/pull/1600
    • Support a custom paramsSerializer on fetchBaseQuery by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1594
    • SSR & rehydration support, suspense foundations by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1277
    • add endpoint, type and forced to BaseQueryApi and prepareHeaders by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1656
    • split off signature without AsyncThunkConfig for better inference by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1644
    • Update createReducer to accept a lazy state init function by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1662
    • add selectInvalidatedBy by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1665
    • Update Yarn from 2.4 to 3.1 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1688
    • allow for circular references by building reducer lazily on first reducer call by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1686
    • Update deps for 1.7 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1692
    • fetchBaseQuery: return nullon empty body for JSON. Add DevWarnings by @phryneas in #1699
    • Add unwrap to QueryActionCreatorResult and update LazyQueryTrigger by @msutkowski in #1701
    • Only set originalArgs if they're not undefined by @phryneas in #1711
    • Treat null as a valid plain object prototype in isPlainObject() in order to sync the util across reduxjs/* repositories by @Ilyklem in #1734
    • export RetryOptions interface from retry.ts by @colemars in #1751
    • fix: api.util.resetApiState should reset useQuery hooks by @phryneas in #1735
    • fix issue where the global RTK object got overwritten in the UMD files by @Antignote in https://github.com/reduxjs/redux-toolkit/pull/1763
    • Update dependencies and selector types by @markerikson in #1772
    • Fix broken sourcemap output due to bad filename replacement by @markerikson in #1773
    • Override unwrap behavior for buildInitiateQuery, update tests by @msutkowski in #1786
    • Fix incorrect RTKQ endpoint definition types for correct selector typings by @markerikson in #1818
    • Use originalArgs in transformResponse by @msutkowski in #1819

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.6.2...v1.7.0

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0-rc.0(Dec 1, 2021)

    This release candidate fixes several assorted small issues and updates dependencies.

    Assuming no other problems pop up, we plan on releasing 1.7 in the next couple days.

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    RTK Query Fixes

    Fixed an issue serializing a query arg of undefined. Related, an empty JSON body now is stored as null instead of undefined.

    There are now dev warnings for potential mistakes in endpoint setup, like a query function that does not return a data field.

    Lazy query trigger promises can now be unwrapped similar to mutations.

    api.util.resetApiState will now clear out cached values in useQuery hooks.

    The RetryOptions interface is now exported, which resolves a TS build error when using the hooks with TS declarations.

    Dependency Updates

    Updated to Immer ^9.0.7, Reselect ^4.1.5, and Thunk ^2.4.1 to pick up the latest types and bug fixes.

    Also, the peer dependencies now list React 18 beta and React-Redux 8 beta as acceptable versions.

    Other Fixes

    The isPlainObject util has been updated to match the implementation in other Redux libs.

    The UMD builds of RTK Query now attach as window.RTKQ instead of overwriting window.RTK.

    Fixed an issue with sourcemap loading due to an incorrect filename replacement.

    What's Changed

    • fetchBaseQuery: return nullon empty body for JSON. Add DevWarnings by @phryneas in #1699
    • Add unwrap to QueryActionCreatorResult and update LazyQueryTrigger by @msutkowski in #1701
    • Only set originalArgs if they're not undefined by @phryneas in #1711
    • Treat null as a valid plain object prototype in isPlainObject() in order to sync the util across reduxjs/* repositories by @Ilyklem in #1734
    • export RetryOptions interface from retry.ts by @colemars in #1751
    • fix: api.util.resetApiState should reset useQuery hooks by @phryneas in #1735
    • fix issue where the global RTK object got overwritten in the UMD files by @Antignote in https://github.com/reduxjs/redux-toolkit/pull/1763
    • Update dependencies and selector types by @markerikson in #1772
    • Fix broken sourcemap output due to bad filename replacement by @markerikson in #1773

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.7.0-beta.1...v1.7.0-rc.0

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0-beta.1(Nov 5, 2021)

    This beta release updates createSlice to avoid potential circular dependency issues by lazy-building its reducer, and updates our runtime dependencies to their latest versions.

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    createSlice Lazy Reducers and Circular Dependencies

    For the last couple years we've specifically recommended using a "feature folder" structure with a single "slice" file of logic per feature, and createSlice makes that pattern really easy - no need to have separate folders and files for /actions and /constants any more.

    The one downside to the "slice file" pattern is in cases when slice A needs to import actions from slice B to respond to them, and slice B also needs to listen to slice A. This circular import then causes runtime errors, because one of the modules will not have finished initializing by the time the other executes the module body. That causes the exports to be undefined, and createSlice throws an error because you can't pass undefined to builder.addCase() in extraReducers. (Or, worse, there's no obvious error and things break later.)

    There are well-known patterns for breaking circular dependencies, typically requiring extracting shared logic into a separate file. For RTK, this usually means calling createAction separately, and importing those action creators into both slices.

    While this is a rarer problem, it's one that can happen in real usage, and it's also been a semi-frequently listed concern from users who didn't want to use RTK.

    We've updated createSlice to now lazily create its reducer function the first time you try to call it. That delay in instantiation should eliminate circular dependencies as a runtime error in createSlice.

    We'd appreciate users trying this out and seeing if it successfully fixes that problem. If you previously extracted some separate actions due to circular dep issues, please try re-consolidating those into the actual slices and see how it works.

    Dependency Updates

    We've updated our deps to the latest versions:

    • Reselect 4.1.x: Reselect has brand-new customization capabilities for selectors, including configuring cache sizes > 1 and the ability to run equality checks on selector results. It also now has completely rewritten TS types that do a much better job of inferring arguments and catch previously broken patterns.
    • Redux Thunk 2.4.0: The thunk middleware also has improved types, as well as an optional "global override" import to modify the type of Dispatch everywhere in the app

    We've also lowered RTK's peer dependency on React from ^16.14 to ^16.9, as we just need hooks to be available.

    What's Changed

    • Update Yarn from 2.4 to 3.1 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1688
    • allow for circular references by building reducer lazily on first reducer call by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1686
    • Update deps for 1.7 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1692

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.7.0-beta.0...v1.7.0-beta.1

    Source code(tar.gz)
    Source code(zip)
  • v1.7.0-beta.0(Oct 29, 2021)

    This release updates RTK Query with support for SSR and rehydration, allows sharing mutation results across components, adds a new currentData field to query results, adds several new options for customizing endpoints and base queries, adds support for async condition options in createAsyncThunk, and updates createSlice/createReducer to accept a "lazy state initializer" function.

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    See the v1.7 beta docs for updated usage guides and API references:

    • https://deploy-preview-1565--redux-starter-kit-docs.netlify.app/

    Changelog

    RTK Query SSR and Rehydration Support

    RTK Query now has support for SSR scenarios, such as the getStaticProps/getServerSideProps APIs in Next.js. Queries can be executed on the server using the existing dispatch(someEndpoint.initiate()) thunks, and then collected using the new await Promise.all(api.getRunningOperationPromises()) method.

    API definitions can then provide an extractRehydrationInfo method that looks for a specific action type containing the fetched data, and return the data to initialize the API cache section of the store state.

    The related api.util.getRunningOperationPromise() API adds a building block that may enable future support for React Suspense as well, and we'd encourage users to experiment with this idea.

    Sharing Mutation Results Across Components

    Mutation hooks provide status of in-progress requests, but as originally designed that information was unique per-component - there was no way for another component to see that request status data. But, we had several requests to enable this use case.

    useMutation hooks now support a fixedCacheKey option that will store the result status in a common location, so multiple components can read the request status if needed.

    This does mean that the data cannot easily be cleaned up automatically, so the mutation status object now includes a reset() function that can be used to clear that data.

    Data Loading Updates

    Query results now include a currentData field, which contains the latest data cached from the server for the current query arg. Additionally, transformResponse now receives the query arg as a parameter. These can be used to add additional derivation logic in cases when a hooks query arg has changed to represent a different value and the existing data no longer conceptually makes sense to keep displaying.

    Data Serialization and Base Query Improvements

    RTK Query originally only did shallow checks for query arg fields to determine if values had changed. This caused issues with infinite loops depending on user input.

    The query hooks now use a "serialized stable value" hook internally to do more consistent comparisons of query args and eliminate those problems.

    Also, fetchBaseQuery now supports a paramsSerializer option that allows customization of query string generation from the provided arguments, which enables better interaction with some backend APIs.

    The BaseQueryApi and prepareheaders args now include fields for endpoint name, type to indicate if it's a query or mutation, and forced to indicate a re-fetch even if there was already a cache entry. These can be used to help determine headers like Cache-Control: no-cache.

    createAsyncThunk Improvements

    The condition option may now be async, which enables scenarios like checking if an existing operation is running and resolving the promise when the other instance is done.

    If an idGenerator function is provided, it will now be given the thunkArg value as a parameter, which enables generating custom IDs based on the request data.

    The createAsyncThunk types were updated to correctly handle type inference when using rejectWithValue().

    Other Improvements

    createSlice and createReducer now accept a "lazy state initializer" function as the initialState argument. If provided, the initializer will be called to produce a new initial state value any time the reducer is given undefined as its state argument. This can be useful for cases like reading from localStorage, as well as testing.

    API objects now have a selectInvalidatedBy function that accepts a root state object and an array of query tag objects, and returns a list of details on endpoints that would be invalidated. This can be used to help implement optimistic updates of paginated lists.

    Related Libraries

    The Redux team has also recently released Reselect 4.1 and Redux Thunk 2.4. Reselect 4.1 contains major improvements to selector options, including cache sizes > 1, and both libraries have improved TS types. We'll update 1.7 to depend on those new versions before release, but you can update your own projects to make sure you have the new functionality and types available as well:

    • https://github.com/reduxjs/reselect/releases/tag/v4.1.0
    • https://github.com/reduxjs/redux-thunk/releases/tag/v2.4.0

    What's Changed

    • fix "isLoading briefly flips back to true" #1519 by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1520
    • feat(createAsyncThunk): async condition by @thorn0 in https://github.com/reduxjs/redux-toolkit/pull/1496
    • add arg to transformResponse by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1521
    • add currentData property to hook results. by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1500
    • use useSerializedStableValue for value comparison by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1533
    • fix(useLazyQuery): added docs for preferCache option by @akashshyamdev in https://github.com/reduxjs/redux-toolkit/pull/1541
    • correctly handle console logs in tests by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1567
    • add reset method to useMutation hook by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1476
    • allow for "shared component results" using the useMutation hook by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1477
    • 🐛 Fix bug with useMutation shared results by @Shrugsy in https://github.com/reduxjs/redux-toolkit/pull/1616
    • pass the ThunkArg to the idGenerator function by @loursbourg in https://github.com/reduxjs/redux-toolkit/pull/1600
    • Support a custom paramsSerializer on fetchBaseQuery by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1594
    • SSR & rehydration support, suspense foundations by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1277
    • add endpoint, type and forced to BaseQueryApi and prepareHeaders by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1656
    • split off signature without AsyncThunkConfig for better inference by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1644
    • Update createReducer to accept a lazy state init function by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/1662
    • add selectInvalidatedBy by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1665

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.6.2...v1.7.0-beta.0

    Source code(tar.gz)
    Source code(zip)
  • v1.6.2(Oct 5, 2021)

    This release fixes several small issues with RTK Query, as well as a regression in the createAsyncThunk types and an issue with sourcemap URLs.

    Changelog

    RTK Query Fixes

    The isLoading flag should only ever be true on the first run of a hook, but would sometimes briefly flip to true on later calls. That should now stay the correct value.

    fetchBaseQuery should now work properly when used in conjunction with node-fetch.

    The BaseQueryApi object now correctly includes the extra argument that was provided when configuring the thunk middleware, if any.

    Other Fixes

    Sourcemap URLs should now be correct, especially for the CommonJS build artifacts.

    createAsyncThunk's types have been updated to correctly infer return values when working with enums.

    Lots of assorted docs tweaks and updates!

    What's Changed

    • Add extra to BaseQueryApi by @ricksanchez in https://github.com/reduxjs/redux-toolkit/pull/1378
    • fix: point sourceMappingURL to correct sourcemaps in build artifacts by @jawadsh123 in https://github.com/reduxjs/redux-toolkit/pull/1459
    • fix: createAsyncThunk union return values fall back to allowing only single member by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1449
    • fix fetchBaseQuery for usage with node-fetch by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1473
    • fix "isLoading briefly flips back to true" #1519 by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1520

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.6.1...v1.6.2

    Source code(tar.gz)
    Source code(zip)
  • v1.6.1(Jul 17, 2021)

    This release improves several edge cases in RTK Query behavior and implementation, deprecates a lesser-used API, and reverts an internal compatability change from 1.6.

    Changelog

    RTK Query Tweaks

    We've made several small tweaks to the RTK Query implementation:

    • fetchBaseQuery now provides a more meaningful error if the response can't be parsed successfully
    • fetchBaseQuery has been tweaked to always read fetch from the global scope, rather than closing over it at creation time. This improves usage with test tools that mock or override fetch at the system level, such as Mirage.
    • The skipToken symbol is now created using Symbol.for(), to get a consistent reference
    • API slices now warn if you try to add more than one reducer with the same reducerPath name
    • An internal hook usage was tweaked to avoid the "don't call useLayoutEffect on the server" warning being printed in SSR

    Also, mutations no longer track the originalArgs value in the store. That value is needed to re-run queries, but since mutations are not re-run, it wasn't needed. This change resolves cases where users were passing a non-serializable value as the mutation argument and then seeing warnings about it being put into the store.

    Technically, this is a breaking change (removes a store property what would have been returned by a selector), but it is a necessary bugfix, and it does not appear anyone was actively using that property. So, we're keeping this as a patch release.

    Generally, the information removed is still available as:

    • a property on the promise returned by dispatch
    • part of the thunk action meta
    • return value of the useMutation hook

    Other Changes

    The typings for createAction and createAsyncThunk have been tweaked to avoid lint warnings about "unbound methods".

    The exported version of getDefaultMiddleware is now marked as deprecated, and will be removed in a future 2.0 release. Use the function passed as the middleware callback instead, which has the correct store types anyway.

    In 1.6, we moved the Immer enableES5 plugin init call from index.ts to be inside of createReducer instead, in an effort to maybe save a few bytes for some users. This has caused some issues for users who still support IE11, possibly due to build config issues. Realistically, we expect that everyone who uses RTK will be calling createReducer, createSlice, or createApi at some point, so there's no real situations where this wouldn't be called anyway. So, we've moved the enableES5 call back to index.ts for consistency. In a future 2.0 release, we will remove that call entirely, and users that still support IE11 will need to call that themselves.

    Changes

    • Error handling of fetchBaseQuery (#1250 - @phryneas)
    • Warn on duplicate reducerPath (#1252 - @phryneas)
    • Deprecate getDefaultMiddleware export (#1258 - @Shrugsy)
    • Typing for unbound functions (#1263 - @ajcrites)
    • Prevent closing over fetch (#1267 - @Shrugsy)
    • Put enableES5 back in index.ts (#1305 - @komar94)
    • Use Symbol.for('skipToken') (#1317 - @phryneas)
    • Remove originalArgs (#1318 - @phryneas)
    • Call useIsomorphicLayoutEffect to fix warnings (#1319 - @markerikson)
    Source code(tar.gz)
    Source code(zip)
  • v1.6.0(Jun 7, 2021)

    This release adds the new RTK Query data fetching APIs to Redux Toolkit. It also adds multiple new options to createAsyncThunk for including meta fields and working with results, updates dependencies to Redux 4.1 and Immer 9, and includes a complete rewrite of our build toolchain with additional "modern" build artifacts in the package.

    While this is a minor release in terms of semver, this is a huge update in terms of functionality, scope, and effort. We're excited about how these new APIs will help our users build better applications with less code and better behavior!

    Installation:

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Upgrade Note: During the alphas, we received some reports of users seeing incorrect types after installing the RTK 1.6 previews. The problems appeared to be caused by multiple versions of the redux package ending up in a project's node_modules folder. If you see this issue, you may need to uninstall and reinstall react-redux with the latest version, to help ensure no redux duplicates are in the package tree.

    Changelog

    RTK Query Data Caching API

    RTK Query is a powerful data fetching and caching tool. It is designed to simplify common cases for loading data in a web application, eliminating the need to hand-write data fetching & caching logic yourself.

    RTK Query is an optional addon included in the Redux Toolkit package, and its functionality is built on top of the other APIs in Redux Toolkit.

    See the RTK Query usage guides and API reference docs for complete information on how to use RTK Query:

    https://redux-toolkit.js.org/rtk-query/overview

    Motivation

    Web applications normally need to fetch data from a server in order to display it. They also usually need to make updates to that data, send those updates to the server, and keep the cached data on the client in sync with the data on the server. This is made more complicated by the need to implement other behaviors used in today's applications:

    • Tracking loading state in order to show UI spinners
    • Avoiding duplicate requests for the same data
    • Optimistic updates to make the UI feel faster
    • Managing cache lifetimes as the user interacts with the UI

    The Redux core has always been very minimal - it's up to developers to write all the actual logic. That means that Redux has never included anything built in to help solve these use cases. The Redux docs have taught some common patterns for dispatching actions around the request lifecycle to track loading state and request results, and Redux Toolkit's createAsyncThunk API was designed to abstract that typical pattern. However, users still have to write significant amounts of reducer logic to manage the loading state and the cached data.

    Over the last couple years, the React community has come to realize that "data fetching and caching" is really a different set of concerns than "state management". While you can use a state management library like Redux to cache data, the use cases are different enough that it's worth using tools that are purpose-built for the data fetching use case.

    RTK Query takes inspiration from other tools that have pioneered solutions for data fetching, like Apollo Client, React Query, Urql, and SWR, but adds a unique approach to its API design:

    • The data fetching and caching logic is built on top of Redux Toolkit's createSlice and createAsyncThunk APIs
    • Because Redux Toolkit is UI-agnostic, RTK Query's functionality can be used with any UI layer
    • API endpoints are defined ahead of time, including how to generate query parameters from arguments and transform responses for caching
    • RTK Query can also generate React hooks that encapsulate the entire data fetching process, provide data and isLoading fields to components, and manage the lifetime of cached data as components mount and unmount
    • RTK Query provides "cache entry lifecycle" options that enable use cases like streaming cache updates via websocket messages after fetching the initial data
    • We have early working examples of code generation of API slices from OpenAPI and GraphQL schemas
    • Finally, RTK Query is completely written in TypeScript, and is designed to provide an excellent TS usage experience

    Basic Usage

    RTK Query is included within the installation of the core Redux Toolkit package. It is available via either of the two entry points below:

    import { createApi } from '@reduxjs/toolkit/query'
    
    /* React-specific entry point that automatically generates
       hooks corresponding to the defined endpoints */
    import { createApi } from '@reduxjs/toolkit/query/react'
    

    For typical usage with React, start by importing createApi and defining an "API slice" that lists the server's base URL and which endpoints we want to interact with:

    import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
    import { Pokemon } from './types'
    
    // Define a service using a base URL and expected endpoints
    export const pokemonApi = createApi({
      reducerPath: 'pokemonApi',
      baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
      endpoints: (builder) => ({
        getPokemonByName: builder.query<Pokemon, string>({
          query: (name) => `pokemon/${name}`,
        }),
      }),
    })
    
    // Export hooks for usage in functional components, which are
    // auto-generated based on the defined endpoints
    export const { useGetPokemonByNameQuery } = pokemonApi
    

    The "API slice" also contains an auto-generated Redux slice reducer and a custom middleware that manages suscription lifetimes. Both of those need to be added to the Redux store:

    import { configureStore } from '@reduxjs/toolkit'
    // Or from '@reduxjs/toolkit/query/react'
    import { setupListeners } from '@reduxjs/toolkit/query'
    import { pokemonApi } from './services/pokemon'
    
    export const store = configureStore({
      reducer: {
        // Add the generated reducer as a specific top-level slice
        [pokemonApi.reducerPath]: pokemonApi.reducer,
      },
      // Adding the api middleware enables caching, invalidation, polling,
      // and other useful features of `rtk-query`.
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware().concat(pokemonApi.middleware),
    })
    
    // optional, but required for refetchOnFocus/refetchOnReconnect behaviors
    // see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
    setupListeners(store.dispatch)
    

    Finally, import the auto-generated React hooks from the API slice into your component file, and call the hooks in your component with any needed parameters. RTK Query will automatically fetch data on mount, re-fetch when parameters change, provide {data, isFetching} values in the result, and re-render the component as those values change:

    import * as React from 'react'
    import { useGetPokemonByNameQuery } from './services/pokemon'
    
    export default function App() {
      // Using a query hook automatically fetches data and returns query values
      const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
      
      // render UI based on data and loading state
    }
    

    Bundle Size

    RTK Query adds a fixed one-time amount to your app's bundle size. Since RTK Query builds on top of Redux Toolkit and React-Redux, the added size varies depending on whether you are already using those in your app. The estimated min+gzip bundle sizes are:

    • If you are using RTK already: ~9kb for RTK Query and ~2kb for the hooks.
    • If you are not using RTK already:
      • Without React: 17 kB for RTK+dependencies+RTK Query
      • With React: 19kB + React-Redux, which is a peer dependency

    Adding additional endpoint definitions should only increase size based on the actual code inside the endpoints definitions, which will typically be just a few bytes.

    The functionality included in RTK Query quickly pays for the added bundle size, and the elimination of hand-written data fetching logic should be a net improvement in size for most meaningful applications.

    Build Tooling Improvements

    We've completely replaced our previous TSDX-based build tooling pipeline with a custom build pipeline based on ESBuild and TypeScript. This should have no visible changes behavior-wise for end users - we've kept the same build artifact names and ES syntax levels. However, it does speed up our own build process, which is important now that we're generating many more output files.

    The published package now also includes a set of "modern" ESM build artifacts that target ES2017 syntax instead of ES5. These files should be smaller than the current "ESM" artifact, which is uses the ES module format but with ES5-level syntax for backwards compatibility.

    Most bundlers should currently pick up the ESM artifact as the default, such as in Create-React-App projects. If you are planning to drop IE11 compatibility, you should be able to modify your bundler config to import the modern artifact instead. Since the modern artifact includes the usual process.env.NODE_ENV checks for build tools to use, we also have pre-compiled versions for "modern dev" and "modern prod" that are suitable for use in browsers or ESM-centric build tools.

    We've also done an optimization pass on both the RTK core and the RTK Query sections to improve tree shaking.

    See this table for details on the generated artifacts, which are available for each of the entry points:

    Redux Toolkit Build Artifacts

    | Filename | Module | Syntax | process.env | Purpose | |----------------------------------------|--------|--------|---------------|------------------------| | <entry-point-name>.cjs.development.js | CJS | ES5 | 'development' | Node / dev | | <entry-point-name>.cjs.production.min.js | CJS | ES5 | 'production' | Node / prod | | <entry-point-name>.esm.js | ESM | ES5 | Embedded | Bundler, legacy syntax | | <entry-point-name>.modern.development.js | ESM | ES2017 | 'development' | Browser module, dev | | <entry-point-name>.modern.js | ESM | ES2017 | Embedded | Bundler, modern syntax | | <entry-point-name>.modern.production.min.js | ESM | ES2017 | 'production' | Browser module, prod | | <entry-point-name>.umd.js | UMD | ES5 | 'development' | Browser script, dev | | <entry-point-name>.umd.min.js | UMD | ES5 | 'production' | Browser script, prod |

    Async Thunk Improvements

    We've made several updates to the createAsyncThunk API to support additional flexibility and use cases.

    Async Thunk meta Support

    createAsyncThunk automatically generates action creators and action types, and then automatically dispatches those actions during execution. This simplifies the process of creating and using thunks, but like all abstractions, also limits flexibility.

    One limitation has been that there was no way to customize the meta field to the actions generated by createAsyncThunk, and some users needed to add additional metadata to actions for use by other middleware.

    We've updated createAsyncThunk to allow adding additional contents to meta. The approach varies based on the action type:

    • pending: there is a new getPendingMeta({arg, requestId}) callback that can be passed as part of the createAsyncThunk options object. This is necessary because the pending action is dispatched before the payload creator is even called.
    • fulfilled: there is a new fulfillWithMeta utility in the payload creator's thunkApi object, which can be used instead of returning the payload directly: return fulfillWithMeta(actualPayload, meta)
    • rejected: the existing rejectWithValue utility now also accepts a meta argument: return rejectWithValue(failedPayload, meta)

    Additional Async Thunk Options

    createAsyncThunk return promises now have a .unwrap() method that returns a promise for the actual result payload, or throws an error if the promise was rejected. This simplifies the use case of working with the thunk result in components.

    createAsyncThunk also now accepts an idGenerator option to let you swap out the default nanoid() ID generation utility for your own, such as uuid4.

    The action creators attached to each thunk should now be callable without needing access to internal implementation details. This enables using them in your own code and tests if needed.

    Dependency Updates

    RTK now depends on Redux 4.1, which shrinks bundle size by extracting error messages from the production builds.

    We've also updated our Immer dependency to 9.x, which has improved TS types.

    See their release notes:

    • https://github.com/reduxjs/redux/releases/tag/v4.1.0
    • https://github.com/immerjs/immer/releases/tag/v9.0.0

    Other Changes

    The miniSerializeError util used by createAsyncThunk is now exported from the main package, as is the new copyWithStructuralSharing util from the RTK Query entry point.

    configureStore now throws errors if the middleware arg is undefined, or if the provided middleware array contains undefined values.

    Thanks

    This release has been the work of many contributors working together. We'd like to recognize their efforts here:

    • @phryneas : Created the RTK Query API, did most of the implementation work, and wrangled reams of angle brackets to get all the TS types working correctly
    • @msutkowski: added additional RTKQ behavior, dogfooded the early alphas, wrote the initial RTKQ preview docs, and created almost all the RTKQ example projects
    • @Shrugsy: wrote extensive sections of the RTKQ usage guide and API reference docs
    • @markerikson: played sounding board for the early API iterations (and generally pestered Lenz and Matt by asking "Can we make that simpler?" every 5 minutes), ported the RTKQ codebase from its alpha repo into the main RTK repo, updated the build tooling to get the correct artifact output, did miscellaneous docs updates and cleanup, and publicized RTKQ everywhere
    • @hardfist: implemented the ESBuild build tooling conversion

    We'd also like to thank:

    • @tannerlinsley, @tkdodo, and the React Query contributors, for pushing the "data caching is not state management" idea forward, helping inspire RTK Query and providing some friendly competition to help us all improve the ecosystem
    • @brandonroberts and @saulmoro for creating integrations between RTK Query and NgRx
    • Everyone else who supplied feedback during our alpha and beta cycles, for helping improve RTKQ's behavior in SSR use cases, finding bugs, and helping shape the API

    Changes

    There have been far too many changes for us to list here individually :) See the complete lists of PRs in the original RTKQ alpha repo and the PRs merged during the RTK 1.6 integration cycle:

    • https://github.com/rtk-incubator/rtk-query/pulls?q=is%3Apr+sort%3Aupdated-desc+is%3Amerged
    • https://github.com/reduxjs/redux-toolkit/pulls?q=is%3Apr+is%3Amerged+base%3Afeature%2Fv1.6-integration+

    The complete codebase changes can be seen here:

    https://github.com/reduxjs/redux-toolkit/compare/v1.5.1...v1.6.0

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-rc.1(Jun 3, 2021)

    This release candidate finalizes the upcoming RTK Query APIs. It adds new options to createAsyncThunk for adding meta fields to thunk-dispatched actions, updates the createApi lifecycle handlers to pass through those meta fields, and removes fields that were deprecated during the alpha process. We've also fleshed out the RTKQ preview docs with significant new content.

    This should be the final preview before the RTK 1.6 final release, barring any unforeseen last-minute bugs. (Note: This is the same content as rc.0, but we found a bug in our build process that had wrong output in that release. Hopefully no more issues!)

    The preview docs are located at https://deploy-preview-1016--redux-starter-kit-docs.netlify.app .

    Installation:

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    Async Thunk meta Support

    createAsyncThunk automatically generates action creators and action types, and then automatically dispatches those actions during execution. This simplifies the process of creating and using thunks, but like all abstractions, also limits flexibility.

    One limitation has been that there was no way to customize the meta field to the actions generated by createAsyncThunk, and some users needed to add additional metadata to actions for use by other middleware.

    We've updated createAsyncThunk to allow adding additional contents to meta. The approach varies based on the action type:

    • pending: there is a new getPendingMeta({arg, requestId}) callback that can be passed as part of the createAsyncThunk options object. This is necessary because the pending action is dispatched before the payload creator is even called.
    • fulfilled: there is a new fulfillWithMeta utility in the payload creator's thunkApi object, which can be used instead of returning the payload directly: return fulfillWithMeta(actualPayload, meta)
    • rejected: the existing rejectWithValue utility now also accepts a meta argument: return rejectWithValue(failedPayload, meta)

    API Lifecycle meta Support

    The createApi cache lifecycle callbacks like onCacheEntryAdded now make the meta field available as part of the promise result, such as cacheDataLoaded.

    Code Cleanup and Types Tweaks

    The fields such as onStart and onSuccess that were deprecated in earlier alphas have been removed.

    The now-unused ApiWithInjectedEndpoints type was removed.

    Various APIs that accept arrays were updated to mark those array parameters as readonly, to help indicate that they shouldn't be mutated, and to ensure that arrays marked as const can be accepted.

    The ApiModules type was modified to prevent a inferred type of this node exceeds the maximum length the compiler will serialize TS error.

    Docs Updates

    We've updated to Docusaurus 2.0-beta.0, which includes Webpack 5. No visible change for you, but faster CI builds for us thanks to build artifact caching! (Our docs builds dropped from around 7 minutes each build down to around 25 seconds, thanks to only changed files being rebuilt.)

    We've also completed filling out the RTK Query API docs.

    Changes

    Code

    • Remove upcoming alpha.3 deprecations (#1052 - @phryneas)
    • createAsyncThunk: support for meta (#1083 - @phryneas)
    • Add baseQueryMeta to thunks, meta to lifecycle results (#1083 - @phryneas)
    • Remove ApiWithInjectedEndpoints references (#1112 - @msutkowski)
    • Add readonly to array-type function params (#1113 - @phryneas)
    • remove Id to force lazy evaluation of API type (#1116 - @phryneas)

    Docs

    • Wayyyy too many docs PRs to even try to list here :) (@Shrugsy)
    • Wayyyy too many examples moved from sandboxes to even try to list here :) (@msutkowski)
    • Match redux config for docusaurus webpack v5 (#1086 - @msutkowski)
    • Some assorted content tweaks (@markerikson)

    https://github.com/reduxjs/redux-toolkit/compare/v1.6.0-beta.0...v1.6.0-rc.1

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-rc.0(Jun 3, 2021)

    This release is broken due to a build misconfiguration - please see rc.1 instead:

    https://github.com/reduxjs/redux-toolkit/releases/tag/v1.6.0-rc.1

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-beta.0(May 22, 2021)

    This beta release improves the in-progress RTK Query APIs. It adds a new onCacheEntryAdded lifecycle callback to enable streaming cache updates, adds per-endpoint cache timeout overrides and additional options for skipping queries, and fixes issues with query arg serialization and build output, We've also fleshed out the RTKQ preview docs with significant new content.

    We are hopeful that this will be the final pre-release with any meaningful API changes, and that the remaining work should just be final polish of the documentation before this goes live.

    The preview docs are located at https://deploy-preview-1016--redux-starter-kit-docs.netlify.app .

    Installation:

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    Cache Entry Lifecycle

    RTK Query is built around standard HTTP endpoint request/response-style API calls. However, today's applications often use a hybrid approach, where initial data is fetched via a request, but then further updates are streamed via a websocket or other persistent connection.

    Endpoint definitions now support an onCacheEntryAdded lifeycle callback. This callback will be executed whenever a new endpoint subscription entry is added to the cache (ie, when a component requests a specific endpoint+params combination that is not currently being loaded).

    The onCacheEntryAdded callback allows you to run additional logic after the initial fetch completes and after the entry is removed from the cache, and provides tools to update the existing cache for this query as needed. The intended use case is to open a websocket-type connection, and update the cached data over time as messages are received. A typical usage might look like:

    export const api = createApi({
      baseQuery: fetchBaseQuery({ baseUrl: "/" }),
      endpoints: (build) => ({
        getMessages: build.query({
          query: (channel) => `messages/${channel}`,
          async onCacheEntryAdded(
            arg,
            { updateCachedData, cacheDataLoaded, cacheEntryRemoved }
          ) {
            // wait for the initial query to resolve before proceeding
            await cacheDataLoaded;
            // Update our query result when messages are received
            const unsubscribe = ChatAPI.subscribeToChannel(
              arg.channelId,
              (message) => {
                // Dispatches an update action with the diff
                updateCachedData((draft) => {
                  draft.push(message);
                });
              }
            );
    
            // Clean up when cache subscription is removed
            await cacheEntryRemoved;
            unsubscribe();
          },
        }),
      }),
    });
    

    This adds significant additional flexibility in interacting with cached data.

    Additional API Polish

    createApi supports a keepUnusedDataFor option to modify the default cache expiration time, but that can now be overridden on a per-endpoint basis as well.

    The selectFromResult option has been reworked so that it receives the standard hook result structure as its input, and you can extract and return whatever pieces of that data are actually needed by this component.

    RTKQ now exports a skipToken value that can be passed to queries as an indicator that the query should be skipped for now, in addition to the existing skip flag option. This is primarily useful for working around some TS inference issues with hook return types.

    The copyWithStructuralSharing util is now exported.

    The updateQueryResult and pathQueryResult util methods have been renamed to updateQueryData and patchQueryData.

    Optimistic updates can now be reverted by calling .undo(), which automatically dispatches the appropriate inverse patch update action.

    Fixes

    The MiddlewareArray type has been tweaked to produce correct behavior when transpiled.

    The default query arg serialization logic now handles nested values correctly.

    Docs Updates

    We've significantly improved the preview RTK Query documentation. We've added pages on "Streaming Updates", "Cached Data", "Customizing Queries", and "Migrating to RTK Query". We've also fleshed out the API references for the generated React hooks, added more details to descriptions of queries and endpoints, and filled out info on how cache lifetime behavior works. Thanks to @Shrugsy for writing most of the docs updates!

    Changes

    Code

    • export Result Definition types (#1022 - @phryneas)
    • add export for copyWithStructuralSharing (#1026 - @phryneas)
    • fix/default serialize query args (#1029 - @phryneas)
    • split up middleware, add OptionalPromise, add cache entry lifecycle (#1034 - - @phryneas)
    • simplify selectFromResult usage (#1035 - @phryneas)
    • fix MiddlewareArray for new build (#1038 - @phryneas)
    • remove last traces of TSDX (#1039 - @phryneas)
    • prevent badly typed Middleware<any> from casting dispatch to any (#1042 - @phryneas)
    • remove alpha.2 deprecation fallbacks (#1051 - @phryneas)
    • add a per-endpoint keepUnusedDataFor option (#1053 - @phryneas)
    • BaseQueryApi.signal is not optional (#1058 - @phryneas)
    • allow using skipSymbol as arg in hooks (#1056 - @phryneas)
    • nest data structure for cacheDataLoaded and queryFulfilled (#1078 - @phryneas)

    Docs

    • Docs - add 'Cached data' concept page (#1036 - @Shrugsy)
    • Docs - RTKQ - Convert codeblocks to TS & enable codeblock transpilation (#1042 - @Shrugsy)
    • Docs - add Streaming Updates page (#1049 - @Shrugsy)
    • Docs - add "Customizing Queries" page (#1057 - @Shrugsy)
    • Docs - Add "Migrating to RTK Query" page (#1060 - @Shrugsy)
    • Docs - add RTK Query content to "Getting Started" page (#1066 - @Shrugsy)
    • Docs - expand explanation of cache lifetime and subscription behavior (#1071 - @Shrugsy)
    • Docs - extend detail for Queries and Endpoints (#1074 - @Shrugsy)

    https://github.com/reduxjs/redux-toolkit/compare/v1.6.0-alpha.2...v1.6.0-beta.0

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-alpha.2(Apr 26, 2021)

    This release fixes a bug with RTK Query cache invalidation, and exposes the useLazyQuerySubscription hook.

    Installation:

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    Invalidation Bugfix

    We saw that RTK Query cache invalidation was actually broken in alpha.1. After investigation, it looks like TypeScript was outputting incorrect code for looping over a set.values() iterator. We've tweaked the logic to work around that.

    Please upgrade to this release ASAP, as invalidation is a key part of RTK Query's functionality.

    useLazyQuerySubscription

    The useLazyQuerySubscription hook was documented, but wasn't actually being included in the output. We've fixed that.

    Additional Build Tweaks

    We're still fiddling with the combination of ESBuild and TypeScript for our recently updated build chain, and have flipped a couple more switches in the process. Should be no user-visible difference.

    Changes

    • Expose useLazyQuerySubscription for endpoints ( #1017 - @Shrugsy)
    • Fix bad transpilation of set iteration breaking invalidation (#1020 - @markerikson)

    https://github.com/reduxjs/redux-toolkit/compare/v1.6.0-alpha.1...v1.6.0-alpha.2

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-alpha.1(Apr 24, 2021)

    This pre-1.6 alpha release integrates the RTK Query source code into the Redux Toolkit repo, publishes the RTK Query APIs as nested endpoints in the @reduxjs/toolkit package, and publishes a docs preview containing the RTK Query API and usage guide docs integrated into the RTK docs site. We've also bumped our Redux dependency to 4.1.0.

    This release also contains the changes from 1.6.0-alpha.0, including Immer 9.x and the improvements to createAsyncThunk and createEntityAdapter.

    Note: we have published additional bugfixes since alpha.1. Please see the releases list for details and be sure to update to @reduxjs/[email protected].

    Installation:

    npm i @reduxjs/[email protected]
    
    yarn add @reduxjs/[email protected]
    

    Changelog

    RTK Query Integration

    RTK Query is a data fetching and caching library built for Redux. It's most similar to React Query, Apollo, Urql, and SWR. The idea is that you just say "here's my URL endpoint and some query params", and it handles the entire process of:

    • Starting to fetch the data when needed
    • Managing loading state
    • Caching the data
    • Re-rendering your component when the loading state changes or the data is available
    • Clearing the cache when the last component that needs the data is unmounted
    • Enabling automatic polling of the data if desired

    So, instead of having to write a bunch of thunks, action creators, reducers, useEffects, and dispatching yourself, you just do:

    // src/services/pokemon.ts
    import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
    
    // Define a service using a base URL and expected endpoints
    export const pokemonApi = createApi({
      reducerPath: 'pokemonApi',
      baseQuery: fetchBaseQuery({ baseUrl: 'https://pokeapi.co/api/v2/' }),
      endpoints: (builder) => ({
    	getPokemonByName: builder.query({
    	  query: (name: string) => `pokemon/${name}`,
    	}),
      }),
    })
    
    // Export hooks for usage in functional components, which are
    // auto-generated based on the defined endpoints
    export const { useGetPokemonByNameQuery } = pokemonApi
    
    
    // src/App.tsx
    import { useGetPokemonByNameQuery } from './services/pokemon'
    
    export default function App() {
      // Using a query hook automatically fetches data and returns query values
      const { data, error, isLoading } = useGetPokemonByNameQuery('bulbasaur')
      
      // render logic here
    }
    

    We originally developed RTK Query as a standalone package at https://github.com/rtk-incubator/rtk-query in order to enable faster iteration during the alpha process.

    Now that the RTK Query APIs have stabilized, we've merged all of the RTK Query source code and docs content back into the main RTK repo. From there, we've updated our build tooling and package publishing to include the RTK Query code inside the @reduxjs/toolkit package, but as separate nested entry points.

    // Existing RTK APIs
    import { createSlice } from '@reduxjs/toolkit'
    // RTK Query APIs, with UI-agnostic logic
    import { createApi } from '@reduxjs/toolkit/query'
    // Same RTK Query APIs, but with React-specific functionality built in
    import { createApi } from '@reduxjs/toolkit/query/react'
    

    If you've been using RTK Query in its standalone alpha package, you should be able to migrate by installing this RTK alpha, and just switching your imports to match the examples above.

    Since these are separate entry points from the root package, you won't pay any bundle size cost unless you specifically import the RTK Query APIs.

    We have not yet done extensive testing of the merged package - that's why this is an alpha! That said, we've successfully been able to locally publish a preview version of the package and use it in a standalone version of the RTKQ "kitchen sink with React" demo app, which is a standard CRA project. We've also verified that the app builds correctly with both TS 4.1 (including named hooks exports using string literal syntax) and TS 4.0 (with just the per-endpoint hook subfields).

    For visualization purposes, here's what the bundle size analysis for that app looks like:

    image

    In general, we believe that this alpha should run correctly in varying environments, but we specifically request that users try this out and let us know if you run into any problems.

    We also expect some additional final tweaks to the RTKQ APIs before 1.6 is released, but do not expect any large breaking changes.

    RTK Query Docs

    We've also merged the RTK Query docs content and added it to a preview version of the RTK docs site. We'll leave this preview up during the RTK 1.6 pre-release process. Here's the links to the primary new docs pages:

    • Tutorial: https://deploy-preview-1016--redux-starter-kit-docs.netlify.app/tutorials/rtk-query
    • Usage guide: https://deploy-preview-1016--redux-starter-kit-docs.netlify.app/usage/rtk-query/queries
    • API reference: https://deploy-preview-1016--redux-starter-kit-docs.netlify.app/api/rtk-query/createApi

    Note that we still need to fill out additional docs content for the RTK APIs and update some of the examples! We'll be working to finish that before the final release.

    Redux 4.1.0

    Since we just released Redux 4.1.0, this release also bumps our Redux dependency to match that. This will shave about 1K off your existing min+gz bundle sizes.

    Changes

    • chore(build): improved build tools (#981 - @hardfist)
    • Migrate RTK Query contents into the RTK repo (#1006 - @markerikson)
    • Restructure RTK files (#1007 - @markerikson)
    • Try to build bundles for RTK Query (core and React) (#1011 - @markerikson)
    • Integrate RTKQ tests (#1012 - @markerikson)
    • Attempt to get TS version selection working (#1013 - @markerikson)
    • Add full types to useMutation's returned callback (#1014 - @Shrugsy)
    • Move RTKQ API docs over (#1015 - @markerikson)

    https://github.com/reduxjs/redux-toolkit/compare/v1.6.0-alpha.0..v1.6.0-alpha.1

    Source code(tar.gz)
    Source code(zip)
  • v1.6.0-alpha.0(Apr 4, 2021)

    This initial pre-1.6 alpha release reworks our build tooling to enable upcoming changes, updates dependencies, adds new entity adapter CRUD methods, and tweaks async thunk options.

    We have several major improvements planned for later pre-1.6 alphas, including merging the "RTK Query" APIs back into RTK itself and making those available as subpackages.

    Changelog

    Build Tooling Updates

    We've replaced our existing TSDX build setup with a new custom setup based on ESBuild + TypeScript (thanks to @hardfist for doing all the work on that!). In theory, we should have all of the same build artifacts we had before, targeting the same browser and ES spec levels. We did add a new set of "modern" build artifacts that target ES2017, with builds for bundlers and browwsers. However, we can't officially list those in package.json yet, as apparently defining an exports key can break Node and is considered a breaking change. We'll look at flipping that on in a future 2.0 release.

    Please let us know if you see any bugs that may be related to the build tooling and bundling changes!

    Dependency Updates

    We've updated Immer to 9.0.x. Also, we've updated Redux to the hot-off-the-presses 4.1.0-alpha.0, which shrinks bundle size by extracted error messages in production. Again, please report any problems you run into.

    New Entity Adapter Replace Methods

    createEntityAdapter already had methods to add, upsert, and update items. We've added setOne and setMany, which let you add or entirely replace existing items.

    Async Thunk Improvements

    createAsyncThunk promises now have a .unwrap() method that returns a promise for the actual result payload, or throws an error if the promise was rejected. This simplifies the use case of working with the thunk result in components.

    createAsyncThunk also now accepts an idGenerator option to let you swap out the default nanoid() ID generation utility for your own, such as uuid4.

    Other Updates

    We've done a bit of internal cleanup in a few functions to simplify and shorten implementations.

    configureStore now checks for accidentally returning undefined for a middleware array, or undefined entries in the array.

    The PreloadedState type should now work better with TS 4.3+.

    Changes

    • Bump Redux to 4.1.0-alpha.0 0169356d
    • Update immer to v9.0.1 (#977) 087d4b62
    • Add idGenerator option to createAsyncThunk (#743) (#976) 309c4bde
    • Add simpler unwrapping of createAsyncThunk promises (#970) 83013703
    • Merge branch 'next' 247f9fe8
    • Remove unnecessary condition (#846) 37d22c49
    • Add check for undefined middleware in configureStore (#959) 86f7eea5
    • chore(build): move tsdx to esbuild (#957) cb0535d4
    • Add setOne and setMany to entity adapter (#969) 795af40a
    • Removed unnecessary sort in sorted_state_adapter.ts#merge() (#960) 44626478
    • Extract common utils from both adapter files (#952) 61ec24c3
    • export AsyncThunkOptions (#950) 7db3e481
    • fix PreloadedState type for TS 4.3 (#949) 9abaec47

    https://github.com/reduxjs/redux-toolkit/compare/v1.5.1...v1.6.0-alpha.0

    Source code(tar.gz)
    Source code(zip)
  • v1.5.1(Mar 26, 2021)

    This release updates createReducer/createSlice to ensure initial state gets frozen, optimizes the performance of the immutability and serializability dev check middleware, and re-exports the original and isDraft APIs from Immer.

    Changes

    Freezing Initial State

    Immer has always frozen its result states in development, and as of Immer 8, does so in production as well. Since both createReducer and createSlice use Immer, all their result states get frozen.

    However, the initial state was never being run through Immer, and thus was never being frozen. That meant it was actually possible to mutate initial state values.

    We now run the initial state through an Immer no-op reducer, just to ensure that it's properly frozen at all times.

    Dev Check Middleware Optimizations

    The immutability and serializability dev check middleware act as safety rails to catch common mistakes. However, both of them do so by running deep recursive checks on all of your Redux state, after every dispatched action. Those deep checks are often very expensive, especially as your state grows larger, and the performance can add noticeable lag in dev. RTK offers options for turning them off or ignoring specific slices of state, and warns if they're taking too long, but those are escape hatches we would rather people not use because they lose the safety benefits.

    In this release, we've optimized both middleware to run significantly faster.

    The immutability middleware now considers frozen objects to be immutable by default, and will stop recursing when it sees a frozen value. This means that in most cases, the runtime of the immutability middleware is effectively 0ms, as it only has to do a few quick checks on your root state slice values without going any deeper. We've also optimized the nested keypath calculation logic, which cuts down on runtime significantly if it does actually have to recurse.

    We've also applied the keypath optimizations to the serializability middleware as well. While this middleware can't benefit from the frozen checks, the keypath optimizations have cut its runtime down by about 70% in benchmarks.

    Additional Immer Re-Exports

    We now export the original and isDraft APIs from Immer for completeness.

    This release also updates the Immer dependency to 8.0.1+ to address a vulnerability in Immer. Our dependency was already 8.0.0+, so strictly speaking no update was necessary - users just needed to update their own local dependencies to get the newer Immer version.

    Docs Updates

    We've made several updates to the RTK docs:

    • The existing tutorials in the RTK docs site have been removed, and we now point to the "Redux Essentials" and the "Redux Fundamentals" tutorials in the Redux core docs so that there's only one place to have to read through tutorials
    • We've added a couple "quick start" tutorial pages that show the bare basics of setting up RTK and using it with TypeScript

    Changelog

    • Export isDraft from Immer (#944 - @markerikson)
    • Optimize dev check middleware performance (#943 - @markerikson)
    • Freeze initial state by passing through Immer (#940 - @markerikson)
    • fix: vulnerability in immer (#909 - @i1skn
    • re-export original from immer (#832- @jackielii)

    https://github.com/reduxjs/redux-toolkit/compare/v1.5.0...v1.5.1

    Source code(tar.gz)
    Source code(zip)
  • v1.5.0(Nov 28, 2020)

    This release updates Immer to v8.x, adds a set of "matcher" utilities to simplify checking if dispatched actions match against a range of known action types, adds additional customization of async thunk error handling, and adds miscellaneous improvements around TS types and some reducer edge cases.

    Changes

    Immer v8

    In RTK v1.4, we upgraded Immer to v7.x, which added a new current API for debugging.

    Immer recently released v8.0.0, which changes its default behavior around auto-freezing state values. Previously, Immer only auto-froze data in development mode, partly under the assumption that freezing would be slower overall. Due to internal changes in Immer 7, Immer now checks if data is frozen and can bail out of some of its processing early. As a result, Immer 8 switches to always freezing return values, even in production, Per discussion in the Immer issues linked from the v8 release announcement, this apparently is actually faster on average.

    This is a noticeable change in behavior, but we consider it not breaking for RTK on the grounds that you shouldn't be mutating state outside of a reducer anyway, so there shouldn't be any visible effect on correctly-written Redux logic.

    We've updated our Immer dependency to v8.x.

    Per the Immer docs on auto-freezing, it may be more efficient to shallowly pre-freeze very large data that won't change by using Immer's freeze utility. RTK now re-exports freeze as well.

    Action Matching Utilities

    In RTK v1.4, we added the ability to write "matching reducers" that can respond to more than one potential action based on a predicate function, such as builder.addMatcher( (action) => action.type.endsWith('/pending'), reducer).

    Many users have asked for the ability to directly list a series of RTK-generated action creators as possible actions to match against. For RTK 1.5, we're adding several utilities that will help handle that process.

    First, we've added isAnyOf(matchers) and isAllOf(matchers). These effectively perform boolean || and && checks, and accept an array containing RTK action creators or action-matching predicates. They return a new matching callback that can be passed to builder.addMatcher().

    const isActionSpecial = (action: any): action is SpecialAction => {
      return action.payload === 'SPECIAL'
    }
    
    const thunkA = createAsyncThunk<string>('a', () => 'result');
    
    // later
    createSlice({
      name,
      initialState,
      reducers: {},
      extraReducers: (builder) => {
        builder.addMatcher(isAllOf(isActionSpecial, thunkA.fulfilled), reducer);
      }
    })
    

    When used with TypeScript, isAllOf and isAnyOf will correctly narrow down the possible type of action based on the actions they match against.

    We've also added a set of matching utilities specifically meant to help check if a given action corresponds to the lifecycle actions dispatched by some specific async thunks. isPending, isFulfilled, isRejected, isRejectedWithValue, and isAsyncThunkAction all accept an array of thunks generated by createAsyncThunk, and will match the corresponding action types from those thunks:

    const thunkA = createAsyncThunk<string>('a', () => 'result')
    const thunkB = createAsyncThunk<string>('b', () => 'result')
        
    // later
    createSlice({
      name,
      initialState,
      reducers: {},
      extraReducers: (builder) => {
        builder.addMatcher(isFulfilled(thunkA, thunkC), reducer);
      }
    })
    

    They can also be used as standard TS type guards:

    if (isFulfilled(action)) {
      // TS will narrow the type of `action` to match the standard "fulfilled" fields
    }
    

    createAsyncThunk Improvements

    We've fixed a bug in the unwrapResult utility where it didn't correctly handle use of rejectWithValue() in the thunk. It will now correctly re-throw the value passed into rejectWithValue().

    The auto-generated requestId is now attached to the promise returned when the thunk is dispatched, as is the arg that was passed into the thunk when it was dispatched.

    We've added a new serializeError callback option to createAsyncThunk. By default, createAsyncThunk will convert thrown errors into a serializable equivalent format, but you can override the serialization and provide your own callback if desired.

    Draft-Safe Selectors

    Memoized selectors created with Reselect's createSelector don't work well with Immer's Proxy-wrapped draft states, because the selectors typically think the Proxy object is the same reference and don't correctly recalculate results as needed.

    We've added a createDraftSafeSelector API that lightly wraps createSelector by checking if the initial argument (usually state) is actually an Immer draft value, and if so, calling current(state) to produce a new JS object. This forces the selector to recalculate the results.

    We've also updated createEntityAdapter's getSelectors API to use these draft-safe selectors.

    In general, using selectors inside of reducers is an unnecessary abstraction - it's fine to access data like state.entities[id].value = 123. However, a number of users have expressed an interest in doing so, so we've made these changes to help accommodate that.

    Other Changes

    We now export our internal isPlainObject implementation.

    If an Immer-powered reducer has null as its value, returning undefined is now accepted.

    TS types for case reducers have been tweaked to allow returning Draft<T> to handle an edge case with generics.

    The TS types for the devTools.serialize option in configureStore have been updated to correctly match the actual values.

    The RTK docs now use a custom Remark plugin created by @phryneas, which allows us to write real TS code for code blocks, compile it to verify it type-checks correctly, and generate a plain JS version of that exact same example, with the TS and JS variations viewable in tabs for each code block.

    You can see that in action in pages like the createSlice API docs:

    https://redux-toolkit.js.org/api/createSlice

    Changelog

    • allow to return undefined for null-states in caseReducers (#631 - @phryneas)
    • fix serialize types (#752 - @blaiz)
    • Allow CaseReducers to also return Draft<T> (#756 - @phryneas)
    • Add requestId property to the promise returned by createAsyncThunk (#784 - @phryneas)
    • Export isPlainObject (#795 - @msutkowski)
    • fix unwrapResult behavior (#704 - @phryneas)
    • isAnyOf/isAllOf HOFs for simple matchers (#788 - @douglas-treadwell)
    • AsyncThunk matchers (#807 - @douglas-treadwell)
    • Update Immer to 8.x (#821 - @markerikson)
    • [entityAdapter] handle draft states in selectors (#815 - @phryneas)
    • cAT: serializeError option (#812 - @phryneas)
    Source code(tar.gz)
    Source code(zip)
  • v1.4.0(Jun 22, 2020)

    This release updates Immer to v7.x, adds new options for defining "matcher" and "default case" reducers, and adds a new option for adding middleware to the store.

    Changes

    Immer v7

    Immer recently released v7.0.0. The main feature is a new current API, which takes a Proxy-wrapped draft value and returns a finalized snapshot of the draft at that point in time.

    Logging draft states in RTK reducers has always been difficult, as browsers display proxies in a hard-to-read format. This utility allows a return to logging partially-updated data to see the results, like console.log(current(state)).

    We've updated our Immer dependency to v7.x, and now export current as part of our public API.

    "Matcher" and "Default Case" Reducers

    createReducer has always been designed to handle exact action types. Both the object form and "builder callback" form let you specify a specific action type string to match against.

    This is by far the most common use case, but we didn't previously have a way to handle matching a range of possible action types based on some criteria. We also had some requests to add some kind of a "default case" handler, similar to the default keyword in a switch statement.

    The builder callback form of createReducer now supports two new methods in addition to the existing builder.addCase method:

    • builder.addMatcher accepts a predicate function that looks like (action: Action) => boolean, and a case reducer. If the matcher returns true, the case reducer will run. Multiple matchers may be added to createReducer, and all matchers that return true will run in the order they were defined after any exact case match has run.
    • builder.addDefaultCase will run a reducer if no other cases or matchers have run.

    Example:

    const increment = createAction('increment')
    const decrement = createAction('decrement')
    createReducer(0, builder =>
      builder
        .addCase(increment, (state, action) => {
          // action is inferred correctly here
        })
        // You can chain calls, or have separate `builder.addCase()` lines each time
        .addCase(decrement, (state, action) => {})
        // You can match a range of action types
        .addMatcher(
          action => action.endsWith('rejected'),
          (state, action) => {}
        )
        // and provide a default case if no other handlers matched
        .addDefaultCase((state, action) => {})
    )
    

    The new builder methods work the same way in the extraReducers field of createSlice as well.

    Middleware Creation

    We already export getDefaultMiddleware to allow you to customize the middleware setup when creating the store. However, running [...getDefaultMiddleware, otherMiddleware] often loses type information when used with TypeScript, and middleware types may need to reference the root state type as well.

    The middleware option for configureStore can now be a callback function that receives a strongly-typed version of getDefaultMiddleware as an argument, and should return the final middleware array. It also includes strongly-typed concat and prepend methods that preserve type information better than spreading arrays:

    const store = configureStore({
      reducer: rootReducer,
      middleware: getDefaultMiddleware => getDefaultMiddleware().concat(logger)
    })
    

    Bug Fixes

    • createAsyncThunk could sometimes skip handling a promise under certain conditions, causing an "Uncaught Promise" warning.
    • The updateMany CRUD method of createEntityAdapter wasn't properly merging together multiple changes for the same item ID

    Typing Updates

    The condition argument for createAsyncThunk is now defined as returning boolean | undefined. The actual code explicitly checks if condition() !== false, so returning undefined is legal, but the typing was too strict.

    We now export the return type for createAsyncThunk for reuse.

    Docs Updates

    We've extensively updated the createReducer and createSlice pages to cover the new builder methods, and configureStore and getDefaultMiddleware to cover the new middleware syntax.

    We've extracted the info on the immutability and serializability dev check middleware into their own separate API reference pages.

    We've added a Usage Guide section on handling "non-serializable value" warnings, including examples of configuration for use with Redux-Persist and React-Redux-Firebase. Related to that, the serializability warning message now includes a link to this section.

    The API reference section now has subcategories for "Store Setup", "Reducers and Actions", and "Other".

    We've enabled Dark Mode for Docusaurus, including tweaks to colors for better contrast.

    Changes

    • Update docs on serializability usage and dev check middleware (@markerikson - #630)
    • add addMatcher to builder notations & actionMatchers argumen… (@phryneas - #610)
    • Add styling for blockquotes on darkmode (@msutkowski - #615)
    • Add section to usage guide on working with non-serializable data (@cloeper - #623)
    • Fixed multiple updates with same id in updateMany (@jakeboone02 - #621)
    • Bump immer to v7, export current util, add usage docs (@mutkowksi - #604)
    • docs: implement dark mode (@sreetamdas - #575)
    • Export return type of createAsyncThunk (@smrq - #574)
    • Prevent unhandled promises in createAsyncThunk (@msutkowski - #570)
    • Adding correctly typed prepend` and concat` to the array… (@phryneas - #559)
    • add middlewareBuilder notation with type-curried arguments to co… (@phryneas - #549)
    • Allow undefined return type for createAsyncThunk options (@melanieseltzer - #595)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.6...v1.4.0

    Source code(tar.gz)
    Source code(zip)
  • v1.3.6(May 9, 2020)

    This release fixes a couple edge cases with Immer usage and reducers, and exposes the typePrefix field from thunks generated by createAsyncThunk.

    Changes

    Immer Reducer Fixes

    The createEntityAdapter CRUD methods can be used as either standalone reducers (in which case they call createNextState() internally) or "mutating" helper functions if given an existing Immer Draft value. However, createReducer always assumed you were using the reducer standalone.

    If you were trying to wrap createReducer and pass in a Draft value, changes inside wouldn't be reflected in the external Draft. We've updated createReducer to check if the incoming state value is actually a `Draft.

    Also, the removeAll CRUD method from createEntityAdapter wasn't working correctly when used as a mutating helper, for similar reasons. We've tweaked the logic there to work right.

    Thunk Type Prefix

    createAsyncThunk accepts a typePrefix string as its first argument, and uses that to generate the pending/fulfilled/rejected action types it dispatches. We had some requests to expose that type string for later usage, so the thunk function now has a thunk.typePrefix field containing that string.

    Changelog

    • expose createAsyncThunk typePrefix parameter on the actionCreator (@phryneas - #546)
    • Allow nested Immer produce statements with createReducer (@AndrewCraswell - #509)
    • fix #541: invoke removeAll mutably within produce (@phryneas - #544)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.5...v1.3.6

    Source code(tar.gz)
    Source code(zip)
  • v1.3.5(Apr 19, 2020)

    This release adds the ability to cancel async thunks before execution, improves TS thunk types, and fixes a broken middleware option name change.

    Changes

    Async Thunk Cancellation

    The createAsyncThunk API already had support for signaling cancellation of in-progress requests via an AbortController. However, there was no way to skip executing the payload creator callback itself, or skip dispatching the pending action.

    We've added a condition option to createAsyncThunk that allows you to run checks before the payload creator is executed, and bail out of the thunk entirely if desired by returning false:

    const fetchUserById = createAsyncThunk(
      'users/fetchByIdStatus',
      async (userId, thunkAPI) => {
        const response = await userAPI.fetchById(userId)
        return response.data
      },
      {
        condition: (userId, { getState, extra }) => {
          const { users } = getState()
          const fetchStatus = users.requests[userId]
          if (fetchStatus === 'fulfilled' || fetchStatus === 'loading') {
            // Already fetched or in progress, don't need to re-fetch
            return false
          }
        }
      }
    )
    

    Thunk Typing Improvements

    We've updated the createAsyncThunk TS types to fix an issue when there is no thunk argument, and to make it easier to wrap createAsyncThunk in your own abstractions. See #486 / #489 for the issues and #502 / #512 for the updates.

    Immutable Middleware Options

    When we inlined the immutable check middleware, we ended up changing the ignore option name to ignoredPaths. We've added handling for ignore for backwards compatibility just in case anyone was relying on that. We've also better documented the options for the serializable check middleware. See #491, #492, and #510 .

    Changelog

    • allow to skip AsyncThunks using a condition callback (@phryneas - #513)
    • payloadCreator arg argument => asyncThunk arg type (@phryneas - #502)
    • export AsyncThunkPayloadCreator type (@phryneas - #512)
    • Update docs, add test, alias ignore->ignoredPaths (@msutkowski - #492)
    • Add missing parameters to docs for serializable middleware (@msutkowski - #510)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.4...v1.3.5

    Source code(tar.gz)
    Source code(zip)
  • v1.3.4(Apr 5, 2020)

    This release updates our internal nanoid implementation, and exports it for general usage.

    Changes

    Export nanoid

    The new createAsyncThunk API we added in v1.3.0 auto-generates a unique request ID every time it's called, so that your reducers can distinguish between separate calls if necessary. To do this, we inlined a copy of the nanoid/non-secure API into RTK.

    The nanoid library just released a new version, so we've updated our inlined copy to match the implementation of nanoid/non-secure as of 3.0.2.

    Since the API is already in the codebase, we've exported it publicly in case it's useful. Usage:

    import { nanoid } from '@reduxjs/toolkit'
    
    console.log(nanoid())
    // 'dgPXxUz_6fWIQBD8XmiSy'
    

    Changelog

    • Update nanoid and export it (@markerikson - #481)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.3...v1.3.4

    Source code(tar.gz)
    Source code(zip)
  • v1.3.3(Apr 4, 2020)

    This release improves serializability checking in actions, and exports additional types.

    Changes

    Action Serializability Checks

    The serializability check middleware checks the contents of all dispatched actions. When we added createAsyncThunk in 1.3, we tried to exclude the meta.args path from those checks, because users may want to pass non-serializable values to their thunks, and the args are automatically added to the actions without the user explicitly putting them there.

    However, the field name was changed from meta.args to meta.arg late in development, and the middleware wasn't updated to match, leading to some false positive warnings. We've fixed that, and added additional middleware options for ignoring paths in actions.

    Type Exports

    Per request, we've exported ThunkDispatch from Redux Thunk, and the rest of the internal typedefs related to entities.

    Changelog

    • Fix/entity types (@markerikson - #477)
    • allow configuration of createSerializableStateInvariantMiddleware ignoredActionPaths, update default value, add tests (@phryneas - #457)
    • Export ThunkDispatch from redux-thunk. (@sammyers - #473)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.2...v1.3.3

    Source code(tar.gz)
    Source code(zip)
  • v1.3.2(Mar 28, 2020)

    When we inlined the immutability check middleware in 1.3.0, we documented the createImmutableInvariantMiddleware API, but forgot to export it. That's been fixed.

    Changelog

    • Export createImmutableStateInvariantMiddleware, fix typo (#449) e3c2cf0

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.1...v1.3.2

    Source code(tar.gz)
    Source code(zip)
  • v1.3.1(Mar 27, 2020)

    This release adds additional argument types for some createEntityAdapter CRUD methods.

    Changes

    createEntityAdapter Insertion APIs

    createEntityAdapter generates three methods that can insert entity objects: setAll, addMany, and upsertMany. All three of them accept an array of entities.

    We expect that a common use case will be to pre-normalize an API response using normalizr, put the parsed entities into an action, and then handle action.payload.articles in a reducer. However, in that case, action.payload.articles is a pre-normalized object, not an array. While you could do articlesAdapter.addMany(state, Object.values(action.payload.articles)), we decided to make those three methods accept a normalized object in addition to an array, allowing articlesAdapter.addMany(state, action.payload.articles) to work correctly.

    createEntityAdapter Usage Guide Docs

    We've also added usage guide examples for createEntityAdapter as well.

    Changelog

    • Add basic createEntityAdapter usage docs (@msutkowski - #442)
    • Add dictionary support to createEntityAdapter many methods (@msutkowski - #444)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0...v1.3.1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0(Mar 24, 2020)

    This release adds two new APIs: createEntityAdapter to help manage normalized state, and createAsyncThunk to abstract common data fetching behavior.

    It also improves bundle size by inlining some of our prior dependencies and fixing cases where dev APIs were accidentally being included in production, as well as using a new version of Immer that tree-shakes better.

    Finally, we've improved the developer experience by tweaking our TS typings for better inference and updating the dev check middleware to warn if checks are taking too much time.

    New APIs

    One of the primary goals for Redux Toolkit has always been to simplify common use cases and reduce "boilerplate" by providing APIs that can replace code you were previously writing out by hand.

    To that end, v1.3.0 adds two new APIs for the common use cases of async data fetching and managing normalized data in the store.

    createAsyncThunk

    The Redux docs have taught that async logic should typically dispatch "three-phase async actions" while doing data fetching: a "start" action before the request is made so that loading UI can be displayed, and then a "success" or "failure" action to handle loading the data or showing an error message. Writing these extra action types is tedious, as is writing thunks that dispatch these actions and differ only by what the async request is.

    Given that this is a very common pattern, we've added a createAsyncThunk API that abstracts this out. It accepts a base action type string and a callback function that returns a Promise, which is primarily intended to be a function that does a data fetch and returns a Promise containing the results. It then auto-generates the request lifecycle action types / creators, and generates a thunk that dispatches those lifecycle actions and runs the fetching callback.

    From there, you can listen for those generated action types in your reducers, and handle loading state as desired.

    createEntityAdapter

    The Redux docs have also advised storing data in a "normalized" state shape, which typically means keeping each type of item in a structure that looks like {ids: [], entities: {} }. However, the Redux core provides no APIs to help manage storing and updating your data using this approach. Many community libraries exist, with varying tradeoffs, but so far we haven't officially recommended any of them.

    Caching data is a hard problem, and not one that we are interested in trying to solve ourselves. However, given that we do recommend this specific pattern, and that Redux Toolkit is intended to help simplify common use cases, we want to provide a minimal set of functionality to help users manage normalized state.

    To help solve this, we've specifically ported the @ngrx/entity library to work with Redux Toolkit, with some modifications.

    The core API function is createEntityAdapter. It generates a set of reducer functions and selectors that know how to work with data that has been stored in that normalized {ids: [], entities: {} } format, and can be customized by passing in a function that returns the ID field for a given item. If you want to keep the item IDs in a sorted order, a comparison function can also be passed in.

    The returned EntityAdapter object contains generated CRUD functions for manipulating items within that state, and generated selector functions that know how to read from that state. You can then use the generated CRUD functions and selectors within your own code.

    There is one very important difference between RTK's implementation and the original @ngrx/entity implementation. With @ngrx/entity, methods like addOne(item, state) accept the data argument first and the state second. With RTK, the argument order has been flipped, so that the methods look like addOne(state, item), and the methods can also accept a standard Redux Toolkit PayloadAction containing the data as the second argument. This allows them to be used as Redux case reducers directly, such as passing them in the reducers argument for createSlice. They can also be used as "mutating" helper functions inside createReducer and createSlice as well, thanks to use of Immer internally.

    Documentation

    We've added new API reference and usage guide sections to the Redux Toolkit docs to cover these new APIs:

    Bundle Size Improvements and Dependency Updates

    Immer 6.0

    Immer has always been the largest chunk of code added to your bundle from using RTK. Until now, RTK specifically depended on Immer 4.x, since 5.x added support for handling Maps and Sets (which aren't useful in a Redux app) and that support added to its bundle size.

    Immer's code was written in a way that kept it from tree-shaking properly. Fortunately, Immer author Michel Weststrate put in some amazing work refactoring the code to better support tree-shaking, and his efforts are now available as Immer 6.0.

    Per the Immer documentation on customizing Immer's capabilities, Immer now uses a plugin architecture internally, and additional functionality has to be explicitly enabled as an opt-in. There are currently three Immer plugins that can be enabled: ES5 support (for environments without ES6 Proxies), Map/Set support, and JSON Patch support.

    Redux Toolkit force-enables ES5 support. This is because we expect RTK to be used in multiple environments that do not support Proxies, such as Internet Explorer and React Native. It's also how Immer previously behaved, so we want to keep that behavior consistent and not break code given that this is a minor release of RTK. (In a hypothetical future major release, we may stop force-enabling the ES5 plugin and ask you to do it if necessary.)

    Overall, this should drop a couple KB off your app's minified bundle size.

    You may choose to enable the other plugins in your app code if that functionality is desired.

    Store Configuration Dependencies

    Since its creation, RTK has depended on leoasis/redux-immutable-state-invariant to throw errors if accidental mutations are detected, and the zalmoxisus/redux-devtools-extension NPM package to handle setup and configuration of the Redux DevTools Extension as the store is created.

    Unfortunately, neither of these dependencies is currently published as ES Modules, and we recently found out that the immutable middleware was actually being included in production bundles despite our attempts to ensure it is excluded.

    Given that the repo for the immutable middleware has had no activity in the last 3 years, we've opted to fork the package and include the code directly inside Redux Toolkit. We've also inlined the tiny-invariant and json-stringify-safe packages that the immutable middleware depended on.

    The DevTools setup package, while tiny, suffers from the same issue, and so we've forked it as well.

    Based on tests locally, these changes should reduce your production bundle sizes by roughly 2.5K minified.

    During the development process, we found that the serializable invariant middleware was partly being included in production. We've decided that both the immutable and serializable middleware should always be no-ops in prod if they're ever included, both to ensure minimum bundle size, and to eliminate any unwanted slowdowns.

    Other Changes

    Type Inference Improvements

    Users reported that it was possible to pass an entity adapter update method as a case reducer even if the slice state type didn't match what the update method expected (#434 ). We've updated the TS types to prevent that from being possible.

    We've also had a number of cases where users had issues with the typings for action payloads depending on whether strictNullChecks: false was set. We've altered our action creator types to improve that behavior.

    Dev Check Middleware Timings

    The immutability and serializability dev check middleware both do deep checks of state on every dispatch in dev mode. With a large state tree, this can sometimes noticeably slow down the app, and it's not immediately clear that the dev check middleware are responsible for this.

    We've updated both middleware to record how much time is spent actually performing the state checks, and they will now log warning messages if the checks take too long to give you a heads-up that you might want to alter the middleware settings or disable them entirely. The delay is configurable, and defaults to 32ms (two UI frames).

    In addition, the serializable middleware now ignores meta.args in every action by default. This is because createAsyncThunk automatically takes any arguments to its payload creator function and inserts them into dispatched actions. Since a user may be reasonably passing non-serializable values as arguments, and they're not intentionally inserting those into actions themselves, it seems sensible to ignore any potential non-serializable values in that field.

    TypeScript Support

    We've dropped support for TS versions earlier than 3.5. Given that 3.8 is out, this shouldn't be a major problem for users.

    Meanwhile, we've also re-exported the TS types from Reselect for convenience.

    Example Usage

    This example demonstrates the typical intended usage of both createEntityAdapter and createAsyncThunk.

    import { createAsyncThunk, createSlice, unwrapResult, createEntityAdapter } from '@reduxjs/toolkit'
    import { userAPI } from './userAPI'
    
    const fetchUserById = createAsyncThunk(
      'users/fetchByIdStatus',
      async (userId) => {
        const response = await userAPI.fetchById(userId)
        return response.data
      }
    )
    
    const usersAdapter = createEntityAdapter()
    
    const usersSlice = createSlice({
      name: 'users',
      initialState: usersAdapter.getInitialState({
        loading: 'idle',
        error: null
      }),
      reducers: {
          usersLoaded: usersAdapter.setAll,
          userDeleted: usersAdapter.removeOne,
      },
      extraReducers: {
        [fetchUserById.pending]: (state, action) => {
          if (state.loading === 'idle') {
            state.loading = 'pending'
          }
        },
        [fetchUserById.fulfilled]: (state, action) => {
          if (state.loading === 'pending') {
            state.loading = 'idle'
            usersAdapter.addOne(state, action.payload)
          }
        },
        [fetchUserById.rejected]: (state, action) => {
          if (state.loading === 'pending') {
            state.loading = 'idle'
            state.error = action.error
          }
        }
      }
    })
    
    const UsersComponent = () => {
      const { users, loading, error } = useSelector(state => state.users)
      const dispatch = useDispatch()
    
      const fetchOneUser = async userId => {
        try {
          const resultAction = await dispatch(fetchUserById(userId))
          const user = unwrapResult(resultAction)
          showToast('success', `Fetched ${user.name}`)
        } catch (err) {
          showToast('error', `Fetch failed: ${err.message}`)
        }
      }
    
      // render UI here
    }
    

    Thanks

    We'd like to thank the many people who contributed and made this release possible:

    • @jonjaques : created the initial version of createAsyncThunk that we based our implementation on
    • The entire NgRx team, particularly @brandonroberts and @MikeRyanDev , for creating @ngrx/entity and allowing us to port it to Redux Toolkit
    • @phryneas: our resident TS wizard, who made innumerable improvements to the TS behavior and createAsyncThunk implementation
    • @msutkowski : lots of feedback on the error handling design for createAsyncThunk
    • @Ethan-Arrowood: pointed us to a novel technique he'd developed for optional overriding of TS generic arguments
    • @mweststrate: the creator of Immer, who made massive improvements to its tree shaking and bundle size capabilities, published a utility for tracking tree shaking sizes of exports, and kept in touch with us on the status of Immer 6
    • All the users who actually tried out the alphas and betas and gave us feedback on bug reports and API design.

    Changelog

    For the complete set of code changes, see:

    and this diff:

    https://github.com/reduxjs/redux-toolkit/compare/v1.2.5...v1.3.0

    For the iterative changes as this release was developed, see the Releases page for the individual release notes.

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-beta.1(Mar 21, 2020)

    This release improves type inference for action creators and for entity adapters that are used as reducers, adds warnings if dev check middleware are taking excessive amounts of time, and adds a new selectById entity selector.

    Changes

    Type Inference Improvements

    Users reported that it was possible to pass an entity adapter update method as a case reducer even if the slice state type didn't match what the update method expected (#434 ). We've updated the TS types to prevent that from being possible.

    We've also had a number of cases where users had issues with the typings for action payloads depending on whether strictNullChecks: false was set. We've altered our action creator types to improve that behavior.

    Meanwhile, we've also re-exported the TS types from Reselect for convenience.

    Dev Check Middleware Timings

    The immutability and serializability dev check middleware both do deep checks of state on every dispatch in dev mode. With a large state tree, this can sometimes noticeably slow down the app, and it's not immediately clear that the dev check middleware are responsible for this.

    We've updated both middleware to record how much time is spent actually performing the state checks, and they will now log warning messages if the checks take too long to give you a heads-up that you might want to alter the middleware settings or disable them entirely. The delay is configurable, and defaults to 32ms (two UI frames).

    Entity Adapter API Changes

    We've added a selectById selector to createEntityAdapter for convenience.

    We've also removed the map() update method, which accepted a callback that returned changes to be applied. It couldn't be used as a reducer (the action would be non-serializable), it's easily re-implemented in userland using the updateMany() update method, and the name map implied a potentially completely different return type of a non-mutating copy, which is not what it actually did.

    Changelog

    • Feature/entity selectors (@markerikson - #440)
    • prevent any-casting of S generic on entityAdapter reducer-like f… (@phryneas - #436)
    • simplify signatures of ActionCreatorWithOptionalPayload (@phryneas - #428)
    • display a warning if immutableStateInvariantMiddleware (@phryneas - #427)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0-beta.0...v1.3.0-beta.1

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-beta.0(Mar 5, 2020)

    This release adds two new APIs: createEntityAdapter to help manage normalized state, and createAsyncThunk to abstract common data fetching behavior.

    It also improves bundle size by fixing cases where APIs were accidentally being included in production and inlining some of our prior dependencies, as well as using a new version of Immer that tree-shakes better.

    Note: this is a beta release. We feel that the APIs are stable and are hopefully ready for a final release soon, and they have been documented and tested. However, we'd still like some additional feedback from users before publishing a final release.

    Please comment in issue #373: Roadmap: RTK v1.3.0 with any feedback on using these new APIs.

    This version is available as @reduxjs/[email protected] on NPM, or @reduxjs/[email protected].

    New APIs

    createAsyncThunk

    The Redux docs have taught that async logic should typically dispatch "three-phase async actions" while doing data fetching: a "start" action before the request is made so that loading UI can be displayed, and then a "success" or "failure" action to handle loading the data or showing an error message. Writing these extra action types is tedious, as is writing thunks that dispatch these actions and differ only by what the async request is.

    Given that this is a very common pattern, we've added a createAsyncThunk API that abstracts this out. It accepts a base action type string and a callback function that returns a Promise, which is primarily intended to be a function that does a data fetch and returns a Promise containing the results. It then auto-generates the request lifecycle action types / creators, and generates a thunk that dispatches those lifecycle actions and runs the fetching callback.

    From there, you can listen for those generated action types in your reducers, and handle loading state as desired.

    createEntityAdapter

    The Redux docs have also advised storing data in a "normalized" state shape, which typically means keeping each type of item in a structure that looks like {ids: [], entities: {} }. However, the Redux core provides no APIs to help manage storing and updating your data using this approach. Many community libraries exist, with varying tradeoffs, but so far we haven't officially recommended any of them.

    Caching data is a hard problem, and not one that we are interested in trying to solve ourselves. However, given that we do recommend this specific pattern, and that Redux Toolkit is intended to help simplify common use cases, we want to provide a minimal set of functionality to help users manage normalized state.

    To help solve this, we've specifically ported the @ngrx/entity library to work with Redux Toolkit, with some modifications.

    The core API function is createEntityAdapter. It generates a set of reducer functions and selectors that know how to work with data that has been stored in that normalized {ids: [], entities: {} } format, and can be customized by passing in a function that returns the ID field for a given item. If you want to keep the item IDs in a sorted order, a comparison function can also be passed in.

    The returned EntityAdapter object contains generated CRUD functions for manipulating items within that state, and generated selector functions that know how to read from that state. You can then use the generated CRUD functions and selectors within your own code.

    There is one very important difference between RTK's implementation and the original @ngrx/entity implementation. With @ngrx/entity, methods like addOne(item, state) accept the data argument first and the state second. With RTK, the argument order has been flipped, so that the methods look like addOne(state, item), and the methods can also accept a standard Redux Toolkit PayloadAction containing the data as the second argument. This allows them to be used as Redux case reducers directly, such as passing them in the reducers argument for createSlice. They can also be used as "mutating" helper functions inside createReducer and createSlice as well, thanks to use of Immer internally.

    Documentation

    See our beta API reference and usage guide docs for details:

    Bundle Size Improvements and Dependency Updates

    Immer 6.0

    Immer has always been the largest chunk of code added to your bundle from using RTK. Until now, RTK specifically depended on Immer 4.x, since 5.x added support for handling Maps and Sets (which aren't useful in a Redux app) and that support added to its bundle size.

    Immer's code was written in a way that kept it from tree-shaking properly. Fortunately, Immer author Michel Weststrate put in some amazing work refactoring the code to better support tree-shaking, and his efforts are now available as Immer 6.0.

    Per the Immer documentation on customizing Immer's capabilities, Immer now uses a plugin architecture internally, and additional functionality has to be explicitly enabled as an opt-in. There are currently three Immer plugins that can be enabled: ES5 support (for environments without ES6 Proxies), Map/Set support, and JSON Patch support.

    Redux Toolkit force-enables ES5 support. This is because we expect RTK to be used in multiple environments that do not support Proxies, such as Internet Explorer and React Native. It's also how Immer previously behaved, so we want to keep that behavior consistent and not break code given that this is a minor release of RTK. (In a hypothetical future major release, we may stop force-enabling the ES5 plugin and ask you to do it if necessary.)

    Overall, this should drop a couple KB off your app's minified bundle size.

    You may choose to enable the other plugins in your app code if that functionality is desired.

    Store Configuration Dependencies

    Since its creation, RTK has depended on leoasis/redux-immutable-state-invariant to throw errors if accidental mutations are detected, and the zalmoxisus/redux-devtools-extension NPM package to handle setup and configuration of the Redux DevTools Extension as the store is created.

    Unfortunately, neither of these dependencies is currently published as ES Modules, and we recently found out that the immutable middleware was actually being included in production bundles despite our attempts to ensure it is excluded.

    Given that the repo for the immutable middleware has had no activity in the last 3 years, we've opted to fork the package and include the code directly inside Redux Toolkit. We've also inlined the tiny-invariant and json-stringify-safe packages that the immutable middleware depended on.

    The DevTools setup package, while tiny, suffers from the same issue, and so we've forked it as well.

    Based on tests locally, these changes should reduce your production bundle sizes by roughly 2.5K minified.

    Changes since Alpha

    This beta release has a few additional changes since the 1.3.0-alpha.10 release.

    createAsyncThunk Error Handling Improvements

    We've spent a lot of time going over the error handling semantics for createAsyncThunk to ensure that errors can be handled outside the thunk, be correctly typed, and that validation errors from a server can be processed correctly. We also now detect if AbortController is available in the environment, and if not, provide a tiny polyfill that suggests adding a real polyfill to your application.

    See PR #393: createAsyncThunk: reject with typed value for much of the discussion and work, as well as the API reference docs.

    Middleware Updates

    We found that the serializable invariant middleware was partly being included in production. We've decided that both the immutable and serializable middleware should always be no-ops in prod, both to ensure minimum bundle size, and to eliminate any unwanted slowdowns.

    In addition, the serializable middleware now ignores meta.args in every action by default. This is because createAsyncThunk automatically takes any arguments to its payload creator function and inserts them into dispatched actions. Since a user may be reasonably passing non-serializable values as arguments, and they're not intentionally inserting those into actions themselves, it seems sensible to ignore any potential non-serializable values in that field.

    Immer 6 final

    We've updated Immer 6 from an alpha build to its final 6.0.1 release. This fixes the ability to use RTK with TS 3.5 and 3.6, as Immer has re-added typings support for those TS versions.

    Other Changes

    TypeScript Support

    We've dropped support for TS versions earlier than 3.5. Given that 3.8 is out, this shouldn't be a major problem for users.

    Example Usage

    This example demonstrates the typical intended usage of both createEntityAdapter and createAsyncThunk.

    import { createAsyncThunk, createSlice, unwrapResult, createEntityAdapter } from '@reduxjs/toolkit'
    import { userAPI } from './userAPI'
    
    const fetchUserById = createAsyncThunk(
      'users/fetchByIdStatus',
      async (userId, { getState }) => {
        const { loading } = getState().users
        if (loading !== 'idle') {
          return
        }
        const response = await userAPI.fetchById(userId)
        return response.data
      }
    )
    
    const usersAdapter = createEntityAdapter()
    
    const usersSlice = createSlice({
      name: 'users',
      initialState: usersAdapter.getInitialState({
        loading: 'idle',
        error: null
      }),
      reducers: {
          usersLoaded: usersAdapter.setAll,
          userDeleted: usersAdapter.removeOne,
      },
      extraReducers: {
        [fetchUserById.pending]: (state, action) => {
          if (state.loading === 'idle') {
            state.loading = 'pending'
          }
        },
        [fetchUserById.fulfilled]: (state, action) => {
          if (state.loading === 'pending') {
            state.loading = 'idle'
            usersAdapter.addOne(state, action.payload)
          }
        },
        [fetchUserById.rejected]: (state, action) => {
          if (state.loading === 'pending') {
            state.loading = 'idle'
            state.error = action.error
          }
        }
      }
    })
    
    const UsersComponent = () => {
      const { users, loading, error } = useSelector(state => state.users)
      const dispatch = useDispatch()
    
      const fetchOneUser = async userId => {
        try {
          const resultAction = await dispatch(fetchUserById(userId))
          const user = unwrapResult(resultAction)
          showToast('success', `Fetched ${user.name}`)
        } catch (err) {
          showToast('error', `Fetch failed: ${err.message}`)
        }
      }
    
      // render UI here
    }
    

    Changelog

    Changes since alpha.10:

    • RFC createAsyncThunk: reject with typed value (@phryneas, @msutkowski - #393)
    • Remove middleware functionality from prod builds (@phryneas - #406)
    • Immer 6 final (@markerikson - #409)
    • Ignore serializability of meta.args by default (@markerikson - #410)

    Changes since alpha.10:

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0-alpha.10...v1.3.0-beta.0

    All 1.3 changes:

    https://github.com/reduxjs/redux-toolkit/compare/v1.2.5...v1.3.0-beta.0

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-alpha.10(Feb 27, 2020)

    This release reduces bundle sizes by updating to the latest Immer 6 alpha to help reduce bundle sizes and inlining the nanoid dependency.

    Note: Due to the Immer upgrade, this RTK alpha version requires at least TypeScript 3.7 if you are consuming it in a TypeScript app. The final version of RTK 1.3 will hopefully support TS 3.5+ once https://github.com/immerjs/immer/pull/541 has been merged in.

    Changes

    Bundle Size Improvements

    Immer has always been the largest chunk of code added to your bundle from using RTK. Until now, RTK specifically depended on Immer 4.x, since 5.x added support for handling Maps and Sets (which aren't useful in a Redux app) and that support added to its bundle size.

    Immer's code was written in a way that kept it from tree-shaking properly. Fortunately, Immer author Michel Weststrate has been hard at work refactoring the code to better support tree-shaking, and his effort are now available as Immer 6.x alpha.

    Per the updated Immer alpha installation docs, Immer now uses a plugin architecture internally, and additional functionality has to be explicitly enabled as an opt-in. There are currently three Immer plugins that can be enabled: ES5 support (for environments without ES6 Proxies), Map/Set support, and JSON Patch support.

    In this alpha, Redux Toolkit force-enables ES5 support. This is because we expect RTK to be used in multiple environments that do not support Proxies, such as Internet Explorer and React Native. It's also how Immer previously behaved, so we want to keep that behavior consistent and not break code given that this is a minor release of RTK. (In a hypothetical future major release, we may stop force-enabling the ES5 plugin and ask you to do it if necessary.)

    Overall, this should drop a couple KB off your app's minified bundle size.

    You may choose to enable the other plugins in your app code if that functionality is desired.

    Inlined nanoid

    We received reports that the nanoid library, which we used for generating unique request IDs in createAsyncThunk, prints warnings on React Native due to a lack of crypto availability. Since we don't need anything cryptographically secure, just reasonably random, we've inlined the function from nanoid/no-secure and dropped the nanoid dependency.

    Documentation

    We've added TypeScript usage guides for createAsyncThunk and createEntityAdapter to the alpha docs:

    Alpha docs: createAsyncThunk and createEntityAdapter TypeScript usage guide

    Changelog

    • Use Immer 6 alpha (@markerikson - #396)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0-alpha.9...v1.3.0-alpha.10

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-alpha.9(Feb 21, 2020)

    This release reduces bundle sizes by forking and inlining the redux-immutable-state-invariant and redux-devtools-extension dependencies, and modifies the types for createEntityAdapter.

    Changes

    Dependency Updates and Bundle Size

    Since its creation, RTK has depended on leoasis/redux-immutable-state-invariant to throw errors if accidental mutations are detected, and the zalmoxisus/redux-devtools-extension NPM package to handle setup and configuration of the Redux DevTools Extension as the store is created.

    Unfortunately, neither of these dependencies is currently published as ES Modules, and we recently found out that the immutable middleware was actually being included in production bundles despite our attempts to ensure it is excluded.

    Given that the repo for the immutable middleware has had no activity in the last 3 years, we've opted to fork the package and include the code directly inside Redux Toolkit. We've also inlined the tiny-invariant and json-stringify-safe packages that the immutable middleware depended on.

    The DevTools setup package, while tiny, suffers from the same issue, and so we've forked it as well.

    Based on tests locally, these changes should reduce your production bundle sizes by roughly 2.5K minified.

    As a future note, Immer is currently being reworked to enable better shakeability, and once that is released, we plan on updating RTK to use the new Immer version as well. This is unlikely to make it into RTK 1.3.0, but we'll put out another update once we've been able to confirm that the changes work for us.

    createEntityAdapter Types

    We made a few more tweaks to the type definitions for createEntityAdapter. Shouldn't be anything breaking, but clarifying the possible overloads for the generated methods.

    Changelog

    • Immutable middleware cleanup (@markerikson - #385)
    • Feature/immutable invariant (@msutkowski - #381)
    • Fork redux-devtools-extension (@markerikson - #384)
    • remove any where applicable (@phryneas - #377)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0-alpha.8...v1.3.0-alpha.9

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-alpha.8(Feb 19, 2020)

    This release fixes a couple edge case bugs with entity update operations, and documents expected update behavior. Also, since the new APIs look to be somewhat stabilized, we've merged the original PR into a v1.3.0 tracking branch where we can integrate additional planned changes.

    Roadmap

    We've put up a v1.3.0 roadmap issue to track other planned work before 1.3.0 is released.

    Changes

    createEntityAdapter Update Logic

    We identified a couple potential bugs and edge cases inside the updateMany method implementation. We've fixed a potential issue that might have appeared when multiple updates were passed in attempting to rename the same entity to different IDs in a row, fixed a wrong type definition for comparer callbacks, and documented expected behavior when ID renames do occur.

    Documentation

    The alpha docs are available at https://deploy-preview-374--redux-starter-kit-docs.netlify.com/. In particular, see the API references for:

    Changelog

    • Port ngrx/entity and add createAsyncThunk (@markerikson, @phryneas - #352) 219be24

    https://github.com/reduxjs/redux-toolkit/compare/v1.2.5...v1.3.0-alpha.8

    Source code(tar.gz)
    Source code(zip)
  • v1.3.0-alpha.7(Feb 18, 2020)

    This release reworks the cancellation functionality in createAsyncThunk.

    Changes

    createAsyncThunk cancellation

    We previously added AbortController support to createAsyncThunk, to allow other code to trigger whatever cancellation might be applicable to the async logic inside.

    The thunk now exits early when the abort() method is called and doesn't keep waiting for the payloadCreator to finish. This should be an improvement especially in cases where the payloadCreator didn't care about the abort signal, but something outside was awaiting the promise from dispatch.

    Also, before this, a non-signal-aware payloadCreator could still finish which would have caused a dispatch of a "fulfilled" action after an "rejected" (abort) action, which was confusing.

    We've also removed the meta.abortReason property as it's no longer possible to override the error in the "rejected" action.

    Changelog

    • createAsyncThunk improvements (@phryneas - #367)

    https://github.com/reduxjs/redux-toolkit/compare/v1.3.0-alpha.6...v1.3.0-alpha.7

    Source code(tar.gz)
    Source code(zip)
Owner
Redux
Redux is a predictable state container for JavaScript apps.
Redux
Skeleton React App configured with Redux store along with redux-thunk, redux persist and form validation using formik and yup

Getting Started with React-Redux App Some Configrations Needed You guys need to modify the baseUrl (path to your server) in the server.js file that is

Usama Sarfraz 10 Aug 23, 2021
A Higher Order Component using react-redux to keep form state in a Redux store

redux-form You build great forms, but do you know HOW users use your forms? Find out with Form Nerd! Professional analytics from the creator of Redux

Redux Form 12.6k Jan 18, 2022
redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state.

redux-immutable redux-immutable is used to create an equivalent function of Redux combineReducers that works with Immutable.js state. When Redux creat

Gajus Kuizinas 1.9k Dec 16, 2021
A chart monitor for Redux DevTools https://www.npmjs.com/package/redux-devtools-chart-monitor

Redux DevTools Chart Monitor This package was merged into redux-devtools monorepo. Please refer to that repository for the latest updates, issues and

Redux 298 Dec 18, 2021
A simple app for study react with redux, redux saga and typescript.

React com Redux, Redux-Saga e TypeScript. ?? Uma aplicação simple para entender o funcionamento do Redux e a melhor maneira de utiliza-lo junto com o

João Marcos Belanga 1 Jan 5, 2022
Redux - Create forms using Redux And React

Exercício de fixação Vamos criar formulários utilizando Redux! \o/ Antes de inic

Márcio Júnior 3 Jan 5, 2022
DevTools for Redux with hot reloading, action replay, and customizable UI

Redux DevTools Developer Tools to power-up Redux development workflow or any other architecture which handles the state change (see integrations). It

Redux 12.3k Jan 13, 2022
Ruthlessly simple bindings to keep react-router and redux in sync

Project Deprecated This project is no longer maintained. For your Redux <-> Router syncing needs with React Router 4+, please see one of these librari

React Community 7.9k Jan 15, 2022
Thunk middleware for Redux

Redux Thunk Thunk middleware for Redux. npm install redux-thunk yarn add redux-thunk Note on 2.x Update Most tutorials today assume that you're using

Redux 16.9k Jan 14, 2022
Logger for Redux

Logger for Redux Now maintained by LogRocket! LogRocket is a production Redux logging tool that lets you replay problems as if they happened in your o

null 5.6k Jan 22, 2022
Selector library for Redux

Reselect Simple “selector” library for Redux (and others) inspired by getters in NuclearJS, subscriptions in re-frame and this proposal from speedskat

Redux 18.4k Jan 17, 2022
An alternative side effect model for Redux apps

redux-saga redux-saga is a library that aims to make application side effects (i.e. asynchronous things like data fetching and impure things like acce

Redux-Saga 22k Jan 14, 2022
Declarative Side Effects for Redux

Redux Data FX Declarative Side Effects for Redux. It helps you keep your business logic and effectful code separate. The idea is simple: in addition o

Matthieu Béteille 53 Jun 30, 2021
RxJS middleware for action side effects in Redux using "Epics"

RxJS-based middleware for Redux. Compose and cancel async actions to create side effects and more. https://redux-observable.js.org Install This has pe

redux-observable 7.8k Jan 18, 2022
Analytics middleware for Redux

redux-analytics Analytics middleware for Redux. $ npm install --save redux-analytics Want to customise your metadata further? Check out redux-tap. Usa

Mark Dalgleish 491 Nov 12, 2021
:recycle: higher order reducer to add undo/redo functionality to redux state containers

redux undo/redo simple undo/redo functionality for redux state containers Protip: Check out the todos-with-undo example or the redux-undo-boilerplate

Daniel Bugl 2.7k Jan 18, 2022
Redux bindings for client-side search

redux-search Higher-order Redux library for searching collections of objects. Search algorithms powered by js-worker-search. Check out the live demo a

Brian Vaughn 1.4k Jan 13, 2022
A mock store for testing Redux async action creators and middleware.

redux-mock-store A mock store for testing Redux async action creators and middleware. The mock store will create an array of dispatched actions which

Redux 2.4k Jan 18, 2022
An i18n solution for React/Redux and React Native projects

redux-react-i18n An i18n solution with plural forms support for Redux/React Workers of all countries, unite! Supported languages list with expected co

Dmitry Erzunov 63 Sep 30, 2021