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

Overview

Redux Toolkit

GitHub Workflow 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.

Comments
  • Add `upsertQueryData` functionality

    Add `upsertQueryData` functionality

    I have a use case where I would like to pass an additional parameter when calling an endpoint, where I do not want this additional parameter to be cached. The first parameter, args, would still be serialized as the cache key as normal.

    Would it be possible to provide an additional field to pass some additional data when calling an endpoint via a hook/initiate? My use case is for calling a query endpoint with initiate.

    Perhaps an additional optional parameter after options? Something likeextraArgs, noCacheArgs, or nonCacheableArgs. I don't know if it makes sense have it on the options parameter, https://redux-toolkit.js.org/rtk-query/api/created-api/endpoints#initiate, but that would work too.

    enhancement 
    opened by chrisjagoda 72
  • 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
  • Add an action listener callback middleware

    Add an action listener callback middleware

    Thunks are easy to use and a good default, but the biggest weakness is that they don't let you respond to dispatched actions. Sagas and observables are very powerful (too powerful for most apps), but they do let you kick off additional logic in response to actions.

    I've been considering adding some kind of middleware that would be in between - something that lets you run callback functions in response to specific actions, but without the complex overhead of sagas and observables.

    I have links to a bunch of existing middleware under the Middleware and Middleware - Async sections of my addons list. One of those might do what we need, or we can take inspiration.

    Glitch appears to have one at handler-middleware.js , which maybe @modernserf could say something about.

    enhancement 
    opened by markerikson 56
  • Discussion: declarative side effects and data fetching approaches

    Discussion: declarative side effects and data fetching approaches

    Currently, Redux Toolkit adds thunks as the default supported approach for any kind of async / side effect behavior, largely because it's the simplest possible approach that works, and because it's also the most widely used Redux async middleware.

    That's a large part of why I'm considering adding some kind of a createAsyncThunk API to abstract common data fetching and action dispatching logic. It matches what we already have built in to RTK, and what many Redux users are already doing.

    @davidkpiano has strongly argued that side effects should be declarative, instead, possibly along the lines of the redux-loop store enhancer.

    I'm open to discussing possible APIs and approaches here. My initial point of concern is that this is a very different kind of API than most Redux users are used to, and it would add an extra level of teaching and documentation to explain.

    Discuss!

    enhancement discussion 
    opened by markerikson 47
  • 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
  • CreateStore return Symbol(observable) params instead of @@observable

    CreateStore return Symbol(observable) params instead of @@observable

    CreateStore return Symbol(observable) params instead of @@observable I am using - "@reduxjs/toolkit": "^1.5.0", Because of it, Redux DevTools 3.0.3 extension doesn't work

    opened by Aidar-Frontend-Developer 38
  • 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
  • FETCH_ERROR with RTK Query, MSW, Vitest

    FETCH_ERROR with RTK Query, MSW, Vitest

    I'm trying to test a component in React that uses RTK Query + MSW + Vitest. It works fine on the browser but while testing RTK Query with vitest it throws this error:

    { status: 'FETCH_ERROR', error: 'TypeError: fetch failed' }

    I've setup a public repo with the configuration i'm using to replicate the error.

    Another error RTK Query throws only while testing is:

    TypeError: Failed to parse URL from /api/test?page=1&limit=10

    This happens when i setup the fetchBaseQuery - baseUrl as empty or as a relative URL. I have to specify 'http://localhost...' or it wont work. But, it works in the browser.

    Repo with the error

    Followed some articles on the matter with no success Searched Stackoverflow and found Searched RTK query repo issues and found a similar issue but with jest instead of vitest I've tried clearing query cache between tests - no success.

    opened by albertofcasuso 0
  • Can't use typed selectors for store created outside toolkit, with dynamic module loading

    Can't use typed selectors for store created outside toolkit, with dynamic module loading

    I'm trying to introduce the toolkit pattern for (among other things) strong typing of selectors/dispatches/cleaner code overall.

    We currently have upstream a

    export const store = createStore({
      initialState: {
        /** initial state */
      },
      extensions: [getThunkExtension()]
    }); 
    

    And I'm forced to adopt a pattern using redux-dynamic-modules whereby I have some module

    export function getCardModule() {
      return {
        id: "viewCard-module",
        reducerMap: {
          viewCard: viewCardReducer
        },
           // initialActions: [getViewsAsync()], todo add the request from here
        finalActions: []
      };
    }
    

    which I'm utilizing by lazy-loading

      const getModules = () => [getReduxModule(devTools), getCardModule()];
    
          <Provider store={store}>
            <DynamicModuleLoader modules={getModules()}>
              <> {children}</>
            </DynamicModuleLoader>
          </Provider>
    

    The viewCardReducer is one created from createSlice as per the toolkit docs.

    As soon as I try to use the existing store as opposed to the one created from configureStore,

    export const store = configureStore({
        reducer: {
            viewCard: viewCardReducer,
        },
    });
    

    I start running into problems.

    For instance my rootState becomes unknown

    export const selectViewCards = (state: RootState) => state.viewCard.views;

    And although I can inspect the redux state using the chrome debugging tools, I can't use the typed selectors

    const viewCardState = useAppSelector(selectViewCards);

    Crashes app, downstream (via webpack extensions) and across error boundaries so no real error log printed

    Yet I can see my empty array with a very ugly

    const viewsss = useSelector((store) => store["viewCard"]?.views);

    Apologies if this has already been answered but I am trying to ingest this entire paradigm only today.

    Assuming I'm stuck using the existing store and dynamically loading modules, how would I go about designing an elegant solution?

    I've read the article on code splitting (among about 8h of other reading today), but can't seem to nail it as I thought that redux-dynamic-modules was supposed to be doing that for me.

    opened by razlani 0
  • Bug: codegen-openapi incorrectly handles multipart/form-data requests

    Bug: codegen-openapi incorrectly handles multipart/form-data requests

    OpenAPI spec:

        "/api/Avatar": {
          "post": {
            "tags": [
              "Avatar"
            ],
            "requestBody": {
              "content": {
                "multipart/form-data": {
                  "schema": {
                    "type": "object",
                    "properties": {
                      "file": {
                        "type": "string",
                        "format": "binary"
                      }
                    }
                  },
                  "encoding": {
                    "file": {
                      "style": "form"
                    }
                  }
                }
              }
            },
            "responses": {
              "200": {
                "description": "Success",
                "content": {
                  "text/plain": {
                    "schema": {
                      "type": "string"
                    }
                  },
                  "application/json": {
                    "schema": {
                      "type": "string"
                    }
                  },
                  "text/json": {
                    "schema": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }      
        },
    

    When you generate API using above specification and send a request you will see that the request content-type is application/json, but should be multipart/form-data. This obviosly results in 415 (Unsupported Media Type) returned from the server.

    opened by ajaskiewiczpl 0
  • fetchBaseQuery doesn't override 'method' field

    fetchBaseQuery doesn't override 'method' field

    Using fetchBaseQuery it's possible to override the headers and other options for all requests in one place except for the method field. It's hardcoded as GET. Is there a reason for this? I have a use-case where all of my requests use POST so it would be convenient to have it overridden in a single place. It could be changed to fallback to GET by default.

    opened by alex-vukov 4
  • Comparing Feature Sets of RTK Query to urql is incorrect/inaccurate

    Comparing Feature Sets of RTK Query to urql is incorrect/inaccurate

    On this section of the page https://redux-toolkit.js.org/rtk-query/comparison#comparing-feature-sets it has a question mark for optimistic updates in urql.

    Optimistic updates, however, do exist in urql. Viz https://formidable.com/open-source/urql/docs/graphcache/cache-updates/#optimistic-updates

    In other minor things, most of the features described as '?' in urql could be implemented via a custom exchange with varying level of difficulty. At least for the easier examples, like Lagged queries, it may be more accurate to say 'requires manual code'.

    opened by Penguibird 0
Releases(v1.9.1)
  • v1.9.1(Nov 30, 2022)

    This bugfix release fixes assorted issues that were reported with RTK 1.9.0, and adds a few additional requested tweaks and improvements.

    Changelog

    Fixes

    The createAsyncThunk.withTypes function was fully broken (it type-checked correctly, but pointed to the wrong function due to a name shadowing issue). That now works correctly.

    The maxRetries option for RTKQ was inadvertently filtering out 0 values, and those are now accepted.

    fulfillWithValue had incorrect types that made it appear as if the data was nested an additional level deeper. The types are now correct.

    The ActionCreatorWithoutPayload type was tweaked to force an error when an action creator is accidentally called with an argument, which happens in cases like onClick={todoAdded}. This avoids accidentally passing values like React event objects as the payload.

    Timer handling for batchActions and autoBatchEnhancer now works in more JS runtime environments.

    Other Changes

    The TagDescription type is now exported from RTKQ.

    API endpoints now have a .name field containing the endpoint name, such as "getPokemon".

    Calling promise.abort() on a createAsyncThunk promise before an async condition resolves will now be treated as if the condition itself returned false, bailing out and not dispatching anything.

    The merge option now receives a third argument containing {arg, baseQueryMeta, fulfilledTimeStamp, requestId}, in case that info is useful in deciding how to merge.

    The @reduxjs/rtk-codemods package has been updated to fix cases where the createSliceBuilder codemod didn't preserve fields with function variable arguments, like [todoAdded]: adapter.addOne. That package has been updated to v0.0.3.

    What's Changed

    • fix createAsyncThunk.withTypes by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2885
    • Update timer polyfills to work in more environments by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2887
    • Retry now checks whether potential retry counts are undefined, rather than boolean, in order to avoid filtering out 0's by @OliverRadini in https://github.com/reduxjs/redux-toolkit/pull/2958
    • Fix multiple small issues with 1.9 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2964
    • fulfillWithValue should infer return value by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2888
    • Fix Identifier/MemberExpression values in createSliceBuilder codemod by @kyletsang in https://github.com/reduxjs/redux-toolkit/pull/2881
    • Additional 1.9.1 fixes by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2965

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.9.0...v1.9.1

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0(Nov 4, 2022)

    This feature release adds several new options for RTK Query's createApi and fetchBaseQuery APIs, adds a new upsertQueryData util, rewrites RTKQ's internals for improved performance, adds a new autoBatchEnhancer, deprecates the "object" syntax for createReducer and createSlice.extraReducers, deprecates and removes broken utils for getting running query promises, improves TS inference, exports additional types, and fixes a number of reported issues.

    npm i @reduxjs/toolkit@latest
    
    yarn add @reduxjs/toolkit@latest
    

    We plan to start work on RTK 2.0 in the next few weeks. RTK 2.0 will focus on dropping legacy build compatibility and deprecated APIs, with some potential new features. See the linked discussion thread and give us feedback on ideas!

    Deprecations and Removals

    Object Argument for createReducer and createSlice.extraReducers

    RTK's createReducer API was originally designed to accept a lookup table of action type strings to case reducers, like { "ADD_TODO" : (state, action) => {} }. We later added the "builder callback" form to allow more flexibility in adding "matchers" and a default handler, and did the same for createSlice.extraReducers.

    We intend to remove the "object" form for both createReducer and createSlice.extraReducers in RTK 2.0. The builder callback form is effectively the same number of lines of code, and works much better with TypeScript.

    Starting with this release, RTK will print a one-time runtime warning for both createReducer and createSlice.extraReducers if you pass in an object argument.

    As an example, this:

    const todoAdded = createAction('todos/todoAdded');
    
    createReducer(initialState, {
      [todoAdded]: (state, action) => {}
    })
    
    createSlice({
      name,
      initialState,
      reducers: {/* case reducers here */},
      extraReducers: {
        [todoAdded]: (state, action) => {}
      }
    })
    

    should be migrated to:

    createReducer(initialState, builder => {
      builder.addCase(todoAdded, (state, action) => {})
    })
    
    createSlice({
      name,
      initialState,
      reducers: {/* case reducers here */},
      extraReducers: builder => {
        builder.addCase(todoAdded, (state, action) => {})
      }
    })
    

    Codemods for Deprecated Object Reducer Syntax

    To simplify upgrading codebases, we've published a set of codemods that will automatically transform the deprecated "object" syntax into the equivalent "builder" syntax.

    The codemods package is available on NPM as @reduxjs/rtk-codemods. It currently contains two codemods: createReducerBuilder and createSliceBuilder.

    To run the codemods against your codebase, run npx @reduxjs/rtk-codemods <TRANSFORM NAME> path/of/files/ or/some**/*glob.js.

    Examples:

    npx @reduxjs/rtk-codemods createReducerBuilder ./src
    
    npx @reduxjs/rtk-codemods createSliceBuilder ./packages/my-app/**/*.ts
    

    We also recommend re-running Prettier on the codebase before committing the changes.

    These codemods should work, but we would greatly appreciate testing and feedback on more real-world codebases!

    Object reducer codemod before/after examples Before:
    createReducer(initialState, {
      [todoAdded1a]: (state, action) => {
        // stuff
      },
      [todoAdded1b]: (state, action) => action.payload,
    });
    
    const slice1 = createSlice({
      name: "a",
      initialState: {},
      extraReducers: {
        [todoAdded1a]: (state, action) => {
          // stuff
        },
        [todoAdded1b]: (state, action) => action.payload,
      }
    })
    

    After:

    createReducer(initialState, (builder) => {
      builder.addCase(todoAdded1a, (state, action) => {
        // stuff
      });
    
      builder.addCase(todoAdded1b, (state, action) => action.payload);
    })
    
    const slice1 = createSlice({
      name: "a",
      initialState: {},
    
      extraReducers: (builder) => {
        builder.addCase(todoAdded1a, (state, action) => {
          // stuff
        });
    
        builder.addCase(todoAdded1b, (state, action) => action.payload);
      }
    })
    

    getRunningOperationPromises Deprecation and Replacement

    In v1.7.0, we added an api.util.getRunningOperationPromises() method for use with SSR scenarios, as well as a singular getRunningOperationPromise() method intended for possible use with React Suspense.

    Unfortunately, in #2477 we realized that both those methods have a fatal flaw - they do not work with multiple stores in SSR.

    As of this release, we are immediately marking getRunningOperationPromises() as deprecated and discouraging its use before we remove it completely in RTK 2.0! It will now throw both runtime and compile errors in development to enforce moving away from using it. However, we are leaving its existing behavior in production builds to avoid actual breakage.

    The getRunningOperationPromise() util was experimental, and as far as we can tell not actually being used by anyone, so we are removing getRunningOperationPromise completely in this release.

    As replacements, RTKQ now includes four new thunks attached to api.util:

    • getRunningQueryThunk(endpointName, queryArgs)
    • getRunningMutationThunk(endpointName, fixedCacheKeyOrRequestId)
    • getRunningQueriesThunk()
    • getRunningMutationsThunk()

    Usages would typically change like this:

    -await Promise.all(api.util.getRunningOperationPromises())
    +await Promise.all(dispatch(api.util.getRunningQueriesThunk()))
    

    Changelog

    New RTK Query createApi Options

    createApi endpoints now have several additional options that can be passed in, some of which are intended to work together.

    merge Option

    RTKQ was built around the assumption that the server is the source of truth, and every refetch replaces the cached data on the client. There are use cases when it would be useful to merge an incoming response into the existing cached data instead, such as pagination or APIs that return varying results over time.

    Query endpoints can now accept a merge(cachedData, responseData) callback that lets you do Immer-powered "mutations" to update the existing cached data instead of replacing it entirely.

    Since RTKQ assumes that each response per key should replace the existing cache entry by default, the merge option is expected to be used with the serializeQueryArgs and forceRefetch options, as described below.

    serializeQueryArgs Option

    RTK Query always serializes the cache key value, and uses the string as the actual key for storing the cache entry. The default serialization is the name of the endpoint, plus either the primitive value or a stable-serialized object. An example might be state.api.queries['getPokemon("pikachu")'].

    RTKQ already supported customization of this serialization behavior at the createApi level. Now, each endpoint can specify its own serializeQueryArgs method.

    The per-endpoint serializeQueryArgs may return either a string, an object, a number, or a boolean. If it's a string, that value will be used as-is. Otherwise, the return value will be run through the default serialization logic. This simplifies the common case of stripping out a couple unwanted object fields from the cache key.

    This option serves two main purposes: leaving out values that are passed in to an endpoint but not really part of the "key" conceptually (like a socket or client instance), and altering cache key behavior to use a single entry for the endpoint (such as in an infinite loading / pagination scenario).

    Also, the defaultSerializeQueryArgs util is now exported.

        getPost: build.query<Post, { id: string; client: MyApiClient }>({
          queryFn: async ({ id, client }) => {
            const post = await client.fetchPost(id)
            return { data: post }
          },
          serializeQueryArgs: ({ queryArgs, endpointDefinition, endpointName }) => {
            const { id } = queryArgs
            // This can return a string, an object, a number, or a boolean.
            // If it returns an object, number or boolean, that value
            // will be serialized automatically via `defaultSerializeQueryArgs`
            return { id } // omit `client` from the cache key
    
            // Alternately, you can use `defaultSerializeQueryArgs`:
            // return defaultSerializeQueryArgs({
            //   endpointName,
            //   queryArgs: { id },
            //   endpointDefinition
            // })
            // Or  create and return a string yourself:
            // return `getPost(${id})`
          },
        }),
    

    forceRefresh option

    Sometimes you may want to force a refetch, even though RTKQ thinks that the serialized query args haven't changed and there's already a fulfilled cache entry.

    This can be used to force RTKQ to actually refetch. One expected use case is an "infinite pagination" scenario where there is one cache entry for the endpoint, different page numbers are given as query args, and the incoming responses are merged into the existing cache entry:

        listItems: build.query<string[], number>({
          query: (pageNumber) => `/listItems?page=${pageNumber}`,
          // Only have one cache entry because the arg always maps to one string
          serializeQueryArgs: ({ endpointName }) => {
            return endpointName
          },
          // Always merge incoming data to the cache entry
          merge: (currentCache, newItems) => {
            currentCache.push(...newItems)
          },
          // Refetch when the page arg changes
          forceRefetch({ currentArg, previousArg }) {
            return currentArg !== previousArg
          },
        }),
    

    transformErrorResponse Option

    Similar to transformResponse, endpoints can now specify a transformErrorResponse option as well.

    upsertQueryData Util

    RTKQ already has an updateQueryData util to synchronously modify the contents of an existing cache entry, but there was no way to create a new cache entry and its metadata programmatically.

    This release adds a new api.util.upsertQueryData API that allows creating a cache entry + its data programmatically. As with the other util methods, this is a thunk that should be dispatched, and you should pass in the exact cache key arg and complete data value you want to insert:

    dispatch(
      api.util.upsertQueryData('post', '3', {
        id: '3',
        title: 'All about cheese.',
        contents: 'I love cheese!',
       })
    )
    

    The dispatch acts like all other RTKQ requests, so the process is async, and the thunk returns a promise that resolves when the upsert is complete.

    RTK Query Performance Improvements

    We've significantly rewritten RTK Query's internal implementation to improve performance, especially in cases where many components with query hooks mount at the same time. The middleware has been "flattened" and runs fewer internal checks against each action, subscription updates are grouped together, and some unnecessary memoized selectors have been removed. One consequence is that forgetting to add the RTKQ middleware now throws an error instead of logging a warning.

    Overall, RTK Query processing time should be noticeably faster than it was in 1.8.

    RTK Query also can take advantage of the new "auto-batch enhancer" (described below) for some additional perf optimization, and we recommend adding that to your Redux store configuration.

    fetchBaseQuery Options

    fetchBaseQuery has several new options for processing requests:

    You can now specify a timeout option for both individual endpoints and fetchBaseQuery . If provided, requests that take longer than this value will automatically abort.

    fetchBaseQuery now supports passing the responseHandler and validateStatus options directly to fetchBaseQuery itself, in addition to accepting it as part of specific endpoints. If provided, these options will be applied as defaults to all requests for that API, which simplifies using them on many endpoints. Providing them for endpoints overrides the global option.

    You can now specify a jsonContentType string that will be used to set the content-type header for a request with a jsonifiable body that does not have an explicit content-type header. Defaults to "application/json".

    You can now specify a isJsonContentType callback that checks to see if the request body or response body should be stringified. The default looks for values like "application/json" and "application/vnd.api+json". You can also now specify responseHandler: 'content-type' to have RTKQ automatically check to see whether a response should be treated as text or JSON.

    The prepareHeaders method can now return void and does not have to return headers.

    Other RTK Query Changes

    The refetch() methods now return a promise that can be awaited.

    Query endpoints can now accept a retryCondition callback as an alternative to maxRetries. If you provide retryCondition, it will be called to determine if RTKQ should retry a failed request again.

    New Auto-Batching Store Enhancer

    There are several different ways to "batch actions" with Redux stores, ranging from reducers to debounced subscriber notifications.

    RTK now includes a new autoBatchEnhancer() store enhancer that uses a variation on the "debounced notification" approach, inspired by React's technique of batching renders and determining if an update is low-priority or high-priority.

    The enhancer looks for any actions tagged with an action.meta[SHOULD_AUTOBATCH] = true flag, and delays notifying subscribers until a queued callback runs. This means that if multiple "auto-batched" actions are dispatched in a row, there will be only one subscriber notification. However, if any "normal-priority" action without that flag are dispatched before the queued callback runs, the enhancer will notify subscribers immediately instead and ignore the callback.

    This allows Redux users to selectively tag certain actions for effective batching behavior, making this purely opt-in on a per-action basis, while retaining normal notification behavior for all other actions.

    The enhancer defaults to using requestAnimationFrame, but can also be configured to use queueMicrotask to run at the end of an event loop tick, setTimeout, or a user-provided callback.

    RTK Query's internals have been updated to mark several key actions as batchable. While the enhancer is purely opt-in, benchmarks indicate that it can help speed up UI performance with RTK Query, especially when rendering many components with query hooks. We recommend adding this enhancer to your store setup if you're using RTK Query:

      const store = configureStore({
      reducer,
      enhancers: (existingEnhancers) => {
        // Add the autobatch enhancer to the store setup
        return existingEnhancers.concat(autoBatchEnhancer())
      },
    })
    

    Additionally, there's a prepareAutoBatched util that can be used to help add the SHOULD_AUTOBATCH flag to actions, designed for use with createSlice:

    const counterSlice = createSlice({
      name: 'counter',
      initialState: { value: 0 } as CounterState,
      reducers: {
        incrementBatched: {
          // Batched, low-priority
          reducer(state) {
            state.value += 1
          },
          // Use the `prepareAutoBatched` utility to automatically
          // add the `action.meta[SHOULD_AUTOBATCH]` field the enhancer needs
          prepare: prepareAutoBatched<void>(),
        },
        // Not batched, normal priority
        decrementUnbatched(state) {
          state.value -= 1
        },
      },
    })
    

    TypeScript Improvements

    RTK 1.9 now requires TS 4.2 or greater, and supports through TS 4.9.

    The action type strings generated by createAction are now full TS template literals when possible.

    There's now a createAsyncThunk.withTypes() method that creates a "pre-typed" version of createAsyncThunk with types like {state, dispatch, extra} baked in. This can be used to simplify customizing createAsyncThunk with the right types once during app setup.

    RTK Query now exports TS types for "pre-typed hook results", for cases when you want to wrap the query/mutation hooks in your own code. Additionally, RTKQ also exports BaseQueryApi and exposes TS-only types for endpoint definitions.

    configureStore now correctly infers changes to the store shape from any store enhancers, such as adding actual extra fields to store.

    RTK now exports additional types from redux-thunk.

    Bug Fixes

    Manually initiated RTKQ promises should resolve correctly.

    Previous API tags are removed before adding new ones, instead of accidentally merging them together.

    invalidateTags works correctly when dealing with persisted query state.

    What's Changed

    • Add isJsonContentType predicate to fetchBaseQuery by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2331
    • Add jsonContentType to fetchBaseQuery options by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2403
    • Add ThunkMiddleware to the re-exported types from redux-thunk by @orta in https://github.com/reduxjs/redux-toolkit/pull/2451
    • add timeout option to fetchBaseQuery by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2143
    • createSlice: use template literal types for action type by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2250
    • add types for manually typing hook results in userland code by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2276
    • Add 'content-type' ResponseHandler by @taylorkline in https://github.com/reduxjs/redux-toolkit/pull/2363
    • feature : endpoint-specific args serializers by @michal-kurz in https://github.com/reduxjs/redux-toolkit/pull/2493
    • RFC: add "merge" functionality by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1059
    • Add runtime deprecation warning for reducer object notation by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2591
    • feat: Add the ability to type StoreEnhancers by @fostyfost in https://github.com/reduxjs/redux-toolkit/pull/2550
    • Batch RTKQ "subscribe on reject" actions, and improve cache collection timer handling by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2599
    • add transformErrorReponse to rtkq endpoints by @dreyks in https://github.com/reduxjs/redux-toolkit/pull/1841
    • Fix manually initiate()d rtk-query promises by @wesen in https://github.com/reduxjs/redux-toolkit/pull/2187
    • Implement codemods for createReducer and createSlice builder by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2602
    • RFC: Expose endpoint types by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1646
    • add createAsyncThunk.withTypes by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2604
    • return promise from query result & hook refetch by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2212
    • retry condition by http error response by @kahirokunn in https://github.com/reduxjs/redux-toolkit/pull/2239
    • implemented upsertQueryData functionality per #1720 #2007 by @barnabasJ in https://github.com/reduxjs/redux-toolkit/pull/2266
    • Consolidate RTKQ middleware to simplify stack size by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2641
    • Try fixing createAsyncThunk issues with TS 4.8 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2643
    • Fix assorted issues with the RTKQ middleware refactor by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2644
    • fix upsertQueryData race situations by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2646
    • Fix upsert by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2669
    • Export the BaseQueryApi interface from rtk-query so it can be used as a type in TypeScript without importing from dist/. by @nsthorat in https://github.com/reduxjs/redux-toolkit/pull/2740
    • Fix retryCondition error. by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2743
    • fix: export ToolkitStore interface from configureStore by @adamhari in https://github.com/reduxjs/redux-toolkit/pull/2750
    • reset dispatchQueued variable after flushing by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2757
    • Add forceRefetch to QueryExtraOptions by @schadenn in https://github.com/reduxjs/redux-toolkit/pull/2663
    • Speed up subscription behavior by tracking state in middleware by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2759
    • prepareHeaders does not need to return headers any more by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2775
    • Add codemods-cli and rewrite "object reducer" codemods by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2768
    • remove alpha compatibility fallbacks by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2777
    • fix skipToken behaviour in useQueryState by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2779
    • fetchBaseQuery: allow headers option by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2778
    • [breaking fix] replace getRunningOperationPromise(s) with getRunning(Query|Queries|Mutation|Mutations)Thunk by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2481
    • General pre-1.9-beta cleanup by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2789
    • Convert "middleware not registered" warning into a full error by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2792
    • Rework endpoint serializeQueryArgs to allow object/number returns by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2835
    • allow for global responseHandler and validateStatus configuration by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2823
    • Fix refetches when sQA returns same value and queryArgs are object by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2844
    • Add an auto-batching enhancer that delays low-pri notifications and use with RTKQ by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2846
    • Check middleware registration directly to avoid persistence issues by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2850
    • Fix "running thunks" types and remove unnecessary RTKQ selectors by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2856
    • Make autobatching notification queueing configurable by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2857
    • Hopefully final v1.9 tweaks by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2859

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.6...v1.9.0

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-rc.1(Nov 2, 2022)

    This release candidate updates the auto-batching enhancer to accept additional options for queuing subscriber notifications, and improves RTKQ perf by removing some unnecessary internal memoized selectors.

    Please try this out and give us feedback (even if it's just "tried updating and everything's fine")! If no further issues come up we intend to publish 1.9 in the next few days.

    npm i @reduxjs/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    Docs updates for 1.9 are complete, and can be viewed here:

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

    Changelog

    Autobatch Enhancer Options

    The initial implementation of the autoBatchEnhancer() always queued delayed subscriber notifications using queueMicrotask. We've updated it to accept alternate options that queue with setTimeout, requestAnimationFrame, or bring-your-own-callback (more similar to redux-batched-subscribe).

    The variation in JS event loop timing behavior (microtasks, macrotasks, and frames) means having these options may be useful in different situations.

    What's Changed

    • Fix "running thunks" types and remove unnecessary RTKQ selectors by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2856
    • Make autobatching notification queueing configurable by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2857

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

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-rc.0(Oct 30, 2022)

    This release candidate includes a new "auto-batching" store enhancer, support for passing some global options to fetchBaseQuery, a fix for forceRefetch behavior, and internal tweaks to checks for missing RTKQ middleware setup.

    Please try this out and give us feedback (even if it's just "tried updating and everything's fine")! If no further issues come up we intend to publish 1.9 in the next few days.

    npm i @reduxjs/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    Docs updates for 1.9 are complete, and can be viewed here:

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

    Changelog

    New Auto-Batching Store Enhancer

    There are several different ways to "batch actions" with Redux stores, ranging from reducers to debounced subscriber notifications.

    RTK now includes a new autoBatchEnhancer() store enhancer that uses a variation on the "debounced notification" approach, inspired by React's technique of batching renders and determining if an update is low-priority or high-priority.

    The enhancer looks for any actions tagged with an action.meta[SHOULD_AUTOBATCH] = true flag, and delays notifying subscribers until the end of the event loop tick. This means that if multiple "auto-batched" actions are dispatched in a row, there will be only one subscriber notification. However, if any "normal-priority" action without that flag is dispatched in the same tick, the enhancer will notify subscribers immediately.

    This allows Redux users to selectively tag certain actions for effective batching behavior, making this purely opt-in on a per-action basis, while retaining normal notification behavior for all other actions.

    RTK Query's internals have been updated to mark several key actions as batchable. While the enhancer is purely opt-in, benchmarks indicate that it can help speed up UI performance with RTK Query, especially when rendering many components with query hooks. We recommend adding it to your store setup:

      const store = configureStore({
      reducer,
      enhancers: (existingEnhancers) => {
        // Add the autobatch enhancer to the store setup
        return existingEnhancers.concat(autoBatchEnhancer())
      },
    })
    

    Additionally, there's a prepareAutoBatched util that can be used to help add the SHOULD_AUTOBATCH flag to actions, designed for use with createSlice:

    const counterSlice = createSlice({
      name: 'counter',
      initialState: { value: 0 } as CounterState,
      reducers: {
        incrementBatched: {
          // Batched, low-priority
          reducer(state) {
            state.value += 1
          },
          // Use the `prepareAutoBatched` utility to automatically
          // add the `action.meta[SHOULD_AUTOBATCH]` field the enhancer needs
          prepare: prepareAutoBatched<void>(),
        },
        // Not batched, normal priority
        decrementUnbatched(state) {
          state.value -= 1
        },
      },
    })
    

    fetchBaseQuery Global Options

    fetchBaseQuery now supports passing the responseHandler, validateStatus, and timeout options directly to fetchBaseQuery itself, in addition to accepting it as part of specific endpoints. If provided, these options will be applied as defaults to all requests for that API, which simplifies using them on many endpoints.

    Other Changes

    Providing serializeQueryArgs and forceRefetch options for an endpoint now works correctly when you pass an object as the cache key argument to a query hook.

    The defaultSerializeQueryArgs util is now exported.

    The endpoint-specific serializeQueryArgs option now allows returning an object or a number instead of just a string. If a string is returned, it will be used as-is for the serialized cache key. If an object or number is returned, that value will be passed to defaultSerializeQueryArgs. This simplifies the common case of wanting to remove a couple fields from the cache key, without needing to call defaultSerializeQueryArgs yourself.

    Internal tweaks to the RTKQ middleware behavior for detecting cases where the middleware has not been added to the store.

    The API docs for the 1.9 preview are fully updated.

    What's Changed

    • Fill out v1.9 remaining docs by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2804
    • Rework endpoint serializeQueryArgs to allow object/number returns by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2835
    • allow for global responseHandler and validateStatus configuration by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2823
    • Fix refetches when sQA returns same value and queryArgs are object by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2844
    • Add an auto-batching enhancer that delays low-pri notifications and use with RTKQ by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2846
    • Check middleware registration directly to avoid persistence issues by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2850

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

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-beta.0(Oct 19, 2022)

    This feature-complete preview release includes several new options for RTK Query API endpoints as well as the ability to "upsert" data, performance improvements to the RTK Query middleware, improvements to fetchBaseQuery behavior, several TS types tweaks and additional type exports, a runtime deprecation warning for the object argument form of createReducer and createSlice.extraReducers, and codemods to update those methods.

    Please try this out and give us feedback (even if it's just "tried updating and everything's fine")! We believe that all changes intended for 1.9 are stable and should work, but as always we'd appreciate real-world checks to confirm that.

    npm i @reduxjs/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    Docs updates for 1.9 are in progress and can be viewed here:

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

    Changes Since Alpha

    Codemods for Deprecated Object Reducer Syntax

    Per the description in 1.9.0-alpha.0, we plan to remove the "object" argument from createReducer and createSlice.extraReducers in the future RTK 2.0 major version. In 1.9.0-alpha.0, we added a one-shot runtime warning to each of those APIs.

    To simplify upgrading codebases, we've published a set of codemods that will automatically transform the deprecated "object" syntax into the equivalent "builder" syntax.

    The codemods package is available on NPM as @reduxjs/rtk-codemods. It currently contains two codemods: createReducerBuilder and createSliceBuilder.

    To run the codemods against your codebase, run npx @reduxjs/rtk-codemods <TRANSFORM NAME> path/of/files/ or/some**/*glob.js.

    Examples:

    npx @reduxjs/rtk-codemods createReducerBuilder ./src
    
    npx @reduxjs/rtk-codemods createSliceBuilder ./packages/my-app/**/*.ts
    

    We also recommend re-running Prettier on the codebase before committing the changes.

    These codemods should work, but we would greatly appreciate testing and feedback on more real-world codebases!

    Before:

    createReducer(initialState, {
      [todoAdded1a]: (state, action) => {
        // stuff
      },
      [todoAdded1b]: (state, action) => action.payload,
    });
    
    const slice1 = createSlice({
      name: "a",
      initialState: {},
      extraReducers: {
        [todoAdded1a]: (state, action) => {
          // stuff
        },
        [todoAdded1b]: (state, action) => action.payload,
      }
    })
    

    After:

    createReducer(initialState, (builder) => {
      builder.addCase(todoAdded1a, (state, action) => {
        // stuff
      });
    
      builder.addCase(todoAdded1b, (state, action) => action.payload);
    })
    
    const slice1 = createSlice({
      name: "a",
      initialState: {},
    
      extraReducers: (builder) => {
        builder.addCase(todoAdded1a, (state, action) => {
          // stuff
        });
    
        builder.addCase(todoAdded1b, (state, action) => action.payload);
      }
    })
    

    getRunningOperationPromises Deprecation and Replacement

    In v1.7.0, we added an api.util.getRunningOperationPromises() method for use with SSR scenarios, as well as a singular getRunningOperationPromise() method intended for possible use with React Suspense.

    Unfortunately, in #2477 we realized that both those methods have a fatal flaw - they do not work with multiple stores in SSR.

    As of this release, we are immediately marking getRunningOperationPromises() as deprecated and discouraging its use before we remove it completely in RTK 2.0! It will now throw both runtime and compile errors in development to enforce moving away from using it. However, we are leaving its existing behavior in production builds to avoid actual breakage.

    The getRunningOperationPromise() util was experimental, and as far as we can tell not actually being used by anyone, so we are removing getRunningOperationPromise completely in this release.

    As replacements, RTKQ now includes four new thunks attached to api.util:

    • getRunningQueryThunk(endpointName, queryArgs)
    • getRunningMutationThunk(endpointName, fixedCacheKeyOrRequestId)
    • getRunningQueriesThunk()
    • getRunningMutationsThunk()

    Usages would typically change like this:

    -await Promise.all(api.util.getRunningOperationPromises())
    +await Promise.all(dispatch(api.util.getRunningQueriesThunk()))
    

    Summary of Alpha Changes

    See the previous release notes for more details.

    RTK Query Options

    • API endpoints:
      • serializeQueryArgs option ( #2493 )
      • merge option ( #1059 )
      • forceRefetch option ( #2663 )
      • transformErrorResponse option ( #1841
    • upsertQueryData util ( #2266 )
    • RTKQ middleware optimization ( #2641, #2759 )
    • fetchBaseQuery options:
      • jsonContentType ( #2403 )
      • timeout ( #2363 )
      • content-type response handler ( #2363 )
      • prepareHeaders can return void ( #2775 )
    • hook triggers return promises ( #2212 )
    • retry conditions by response ( #2239 )

    TS Types

    • action types are now template literals ( #2250 )
    • Store enhancer types ( #2550 )
    • createAsyncThunk.withTypes ( #2604 )
    • Several additional exported types:
      • #2276
      • #1646
      • #2740

    TS Support Matrix

    Redux Toolkit now requires TypeScript 4.2 or higher, and works correctly with TS 4.8.

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-alpha.2(Oct 9, 2022)

    This feature preview release fixes broken behavior in the new upsertQueryData API, fixes behavior with the serializeQueryArgs+merge combination by adding a new forceRefetch option, rewrites the internal subscription tracking to speed up mount/update times, adds new TS type exports, and includes the bug fixes from 1.8.6.

    Changelog

    upsertQueryData Fix

    We released the new upsertQueryData util in 1.9.0-alpha.1, but the behavior didn't actually work as intended in some cases. We've tweaked the implementation and it now should work correctly. Please try it out and let us know!

    New forceRefresh option and Infinite Loading Usages

    In earlier alphas, we added a new serializeQueryArgs endpoint option to allow customization of cache keys. This serves two purposes: leaving out values that are passed in to an endpoint but not really part of the "key" conceptually (like a socket or client instance), and altering cache key behavior to use a single entry for the endpoint such as in an infinite loading / pagination scenario.

    Along with that, we also added a merge option that lets you modify the contents of an existing cache entry when new data is received, instead always replacing it.

    Due to the existing internal logic, these two options are insufficient for the infinite loading / pagination case. For example, changing useGetItemsQuery(pageNum) from 1 to 2 starts the checks for fetching new data, but it bails out internally because there's already a cache entry that is status: fulfilled for that endpoint and cache key.

    We've added an additional forceRefresh call back that receives {currentArg, previousArg, state, endpointState} as arguments. Use this in combination with the other options to force this endpoint to refetch when args change despite a single cache entry already existing, such as this example:

    forceRefetch({currentArg, previousArg}) {
      // Assume these are page numbers
      return currentArg !== previousArg
    },
    serializeQueryArgs({endpointName}) {
      // Will only have one cache entry for this endpoint, because of the consistent name
      return endpointName
    },
    merge(currentCacheData, responseData) {
      // Always add incoming data to the existing cache entry
      currentCacheData.push(...responseData)
    }
    

    The forceRefresh option may also be useful in other app-specific scenarios as well.

    Internal Subscription Logic Rewrite

    RTKQ tracks subscription entries, and thus far has done so by saving them in the Redux state and updating that by dispatching actions as each query hook loads. We've seen that this can be a performance bottleneck in edge cases where hundreds of query hooks are being mounted at once. (This shouldn't be a concern in most apps, but some users were stress-testing things :) )

    We've reworked the internal RTKQ middleware logic to track most of the subscription data inside the middleware and sync it to the Redux store at the end of an event loop tick. This should speed up those large list edge cases by cutting 90% of the startup time.

    What's Changed

    • fix upsertQueryData race situations by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2646
    • Fix upsert by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2669
    • Export the BaseQueryApi interface from rtk-query so it can be used as a type in TypeScript without importing from dist/. by @nsthorat in https://github.com/reduxjs/redux-toolkit/pull/2740
    • Fix retryCondition error. by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2743
    • fix: export ToolkitStore interface from configureStore by @adamhari in https://github.com/reduxjs/redux-toolkit/pull/2750
    • Fix the dispatch type inference to correctly handle read-only middleware arrays by @dokmic in https://github.com/reduxjs/redux-toolkit/pull/2629
    • fix(toolkit): export "ThunkMiddleware" from redux-thunk by @VinceOPS in https://github.com/reduxjs/redux-toolkit/pull/2745
    • Remove previous api tags before adding new provided tags by @Bezmehrabi in https://github.com/reduxjs/redux-toolkit/pull/2702
    • reset dispatchQueued variable after flushing by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2757
    • Fix invalidateTags by @manceau-jb in https://github.com/reduxjs/redux-toolkit/pull/2721
    • Add forceRefetch to QueryExtraOptions by @schadenn in https://github.com/reduxjs/redux-toolkit/pull/2663
    • Speed up subscription behavior by tracking state in middleware by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2759

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.9.0-alpha.1...v1.9.0-alpha.2

    Source code(tar.gz)
    Source code(zip)
  • v1.8.6(Oct 9, 2022)

    This bugfix release fixes a couple of issues with RTKQ endpoint tags not invalidating correctly, and tweaks the dispatch type inference to handle more variations of arrays.

    What's Changed

    • Fix the dispatch type inference to correctly handle read-only middleware arrays by @dokmic in https://github.com/reduxjs/redux-toolkit/pull/2629
    • fix(toolkit): export "ThunkMiddleware" from redux-thunk by @VinceOPS in https://github.com/reduxjs/redux-toolkit/pull/2745
    • Remove previous api tags before adding new provided tags by @Bezmehrabi in https://github.com/reduxjs/redux-toolkit/pull/2702
    • Fix invalidateTags by @manceau-jb in https://github.com/reduxjs/redux-toolkit/pull/2721

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.5...v1.8.6

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-alpha.1(Aug 28, 2022)

    This feature preview release adds new options and improves behavior for RTK Query.

    As of this alpha, RTK 1.9 is feature-complete and we do not expect additional meaningful changes. The remaining work is filling out docs and preparing the "object reducer" codemods for release alongside 1.9.

    Still no specific ETA for release, but we hope for Soon (TM) :)

    Changelog

    upsertQueryData API

    RTKQ already has an updateQueryData util to synchronously modify the contents of an existing cache entry, but there was no way to create a new cache entry and its metadata programmatically.

    This release adds a new api.util.upsertQueryData API that allows creating a cache entry + its data programmatically. As with the other util methods, this is a thunk that should be dispatched, and you should pass in the exact cache key arg and complete data value you want to insert:

    dispatch(
      api.util.upsertQueryData('post', '3', {
        id: '3',
        title: 'All about cheese.',
        contents: 'I love cheese!',
       })
    )
    

    RTKQ Middleware Performance Optimizations

    RTKQ automatically generates a Redux middleware for each "API slice" / createApi call. That middleware itself has been made up of 7 individual middleware internally composed into the final middleware, with each individual middleware responsible for a different task like managing polling or cache lifetimes.

    While this worked well for encapsulating responsibilities, it also meant that every dispatched Redux action had to go through 7 additional middleware. This added multiple function calls to each dispatch's stack trace, and even if there isn't a noticeable perf hit, it wasn't efficient. We've also had some reports that users with multiple API slices were occasionally seeing "Maximum call stack size exceeded" errors.

    We've rewritten the internals of the middleware to be more efficient. Actions now only receive extra processing if they're actually related to the API slice itself, and that processing is done via a loop over handling logic at the end of the middleware unwind phase, rather than nesting function calls through multiple sub-middleware. That should keep the call stack shorter in the cases where API actions really are being processed.

    Other RTKQ Updates

    The refetch() methods now return a promise that can be awaited.

    Query endpoints can now accept a retryCondition callback as an alternative to maxRetries. If you provide retryCondition, it will be called to determine if RTKQ should retry a failed request again.

    What's Changed

    • return promise from query result & hook refetch by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2212
    • retry condition by http error response by @kahirokunn in https://github.com/reduxjs/redux-toolkit/pull/2239
    • implemented upsertQueryData functionality per #1720 #2007 by @barnabasJ in https://github.com/reduxjs/redux-toolkit/pull/2266
    • Consolidate RTKQ middleware to simplify stack size by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2641
    • Add TS 4.8 to the test matrix by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2642
    • Try fixing createAsyncThunk issues with TS 4.8 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2643
    • Fix assorted issues with the RTKQ middleware refactor by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2644

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

    Source code(tar.gz)
    Source code(zip)
  • v1.9.0-alpha.0(Aug 19, 2022)

    This feature preview release adds new options and improves behavior for RTK Query, adds a runtime deprecation for the "object" form of createReducer/createSlice.extraReducers, adds the ability to define a "pre-typed" version of createAsyncThunk, improves TS inference of store enhancers, and exports additional TS types.

    We hope to add a couple additional RTKQ options as part of the final 1.9 release, including an upsertQueryData util. See the RTK 1.9 milestone for remaining items. No hard ETA yet, but ideally we'd like to publish 1.9 within the next couple weeks if we can wrap things up.

    Notable Changes

    Some highlights for this alpha:

    RTKQ merge Option

    RTKQ was built around the assumption that the server is the source of truth, and every refetch replaces the cached data on the client. There are use cases when it would be useful to merge an incoming response into the existing cached data instead, such as pagination or APIs that return varying results over time.

    Query endpoints can now accept a merge(cachedData, responseData) callback that lets you do Immer-powered "mutations" to update the existing cached data instead of replacing it entirely.

    Object Reducer Deprecation Warning

    RTK's createReducer API was originally designed to accept a lookup table of action type strings to case reducers, like { "ADD_TODO" : (state, action) => {} }. We later added the "builder callback" form to allow more flexibility in adding "matchers" and a default handler, and did the same for createSlice.extraReducers.

    We intend to remove the "object" form for both createReducer and createSlice.extraReducers in RTK 2.0. The builder callback form is effectively the same number of lines of code, and works much better with TypeScript.

    Starting with this release, RTK will print a one-time runtime warning for both createReducer and createSlice.extraReducers if you pass in an object argument.

    As an example, this:

    const todoAdded = createAction('todos/todoAdded');
    
    createReducer(initialState, {
      [todoAdded]: (state, action) => {}
    })
    
    createSlice({
      name,
      initialState,
      reducers: {/* case reducers here */},
      extraReducers: {
        [todoAdded]: (state, action) => {}
      }
    })
    

    should be migrated to:

    createReducer(initialState, builder => {
      builder.addCase(todoAdded, (state, action) => {})
    })
    
    createSlice({
      name,
      initialState,
      reducers: {/* case reducers here */},
      extraReducers: builder => {
        builder.addCase(todoAdded, (state, action) => {})
      }
    })
    

    We have initial codemods in the repo that will help rewrite the object form to the builder form, and we'll publish those with instructions alongside 1.9 when it goes final.

    RTKQ Internal Improvements

    When query hooks mount, they dispatch actions to subscribe to the relevant data. The first hook to do so will dispatch a "subscription/fulfilled" action, and all further hooks asking for the same cache key will dispatch "subscription/rejected" actions. Both cause the reducer logic to add another entry to the subscription tracking.

    The dispatching of individual "subscription/rejected" actions was causing perf issues when many components mounted at once, due to the number of extra dispatches. RTKQ now batches those into a single combined action per event loop tick, which improves perf for some many-component use cases noticeably.

    TS Types

    configureStore now correctly infers changes to the store shape from any store enhancers.

    There's now a createAsyncThunk.withTypes() method that can be used to create a "pre-typed" version of createAsyncThunk with types like {state, dispatch, extra} baked in.

    What's Changed

    • Add isJsonContentType predicate to fetchBaseQuery by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2331
    • Add jsonContentType to fetchBaseQuery options by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2403
    • Add ThunkMiddleware to the re-exported types from redux-thunk by @orta in https://github.com/reduxjs/redux-toolkit/pull/2451
    • add timeout option to fetchBaseQuery by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2143
    • createSlice: use template literal types for action type by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2250
    • add types for manually typing hook results in userland code by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2276
    • Add 'content-type' ResponseHandler by @taylorkline in https://github.com/reduxjs/redux-toolkit/pull/2363
    • feature : endpoint-specific args serializers by @michal-kurz in https://github.com/reduxjs/redux-toolkit/pull/2493
    • RFC: add "merge" functionality by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1059
    • Add runtime deprecation warning for reducer object notation by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2591
    • feat: Add the ability to type StoreEnhancers by @fostyfost in https://github.com/reduxjs/redux-toolkit/pull/2550
    • Batch RTKQ "subscribe on reject" actions, and improve cache collection timer handling by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2599
    • add transformErrorReponse to rtkq endpoints by @dreyks in https://github.com/reduxjs/redux-toolkit/pull/1841
    • Fix manually initiate()d rtk-query promises by @wesen in https://github.com/reduxjs/redux-toolkit/pull/2187
    • Implement codemods for createReducer and createSlice builder by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2602
    • RFC: Expose endpoint types by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1646
    • add createAsyncThunk.withTypes by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2604

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.5...v1.9.0-alpha.0

    Source code(tar.gz)
    Source code(zip)
  • v1.8.5(Aug 19, 2022)

    This bugfix releas fixes an issue with large keepUnusedDataFor values overflowing JS timers, exports the types for the Redux DevTools Extension option, and and improves behavior of URL string generation.

    Changelog

    keepUnusedDataFor Timer Fix

    keepUnusedDataFor accepts a value in seconds. When there are no more active subscriptions for a piece of data, RTKQ will set a timer using setTimeout, and keepUnusedDataFor * 1000 as the timer value.

    We've been advising users that if they want to keep data in the cache forever that they should use a very large value for keepUnusedDataFor, such as 10 years in seconds.

    However, it turns out that JS engines use a 32-bit signed int for timers, and 32-bits in milliseconds is only 24.8 days. If a timer is given a value larger than that, it triggers immediately.

    We've updated the internal logic to clamp the keepUnusedDataFor value to be between 0 and THIRTY_TWO_BIT_MAX_TIMER_SECONDS - 1.

    Note that in RTK 1.9 (coming soon), RTKQ will also accept Infinity as a special keepUnusedDataFor value to indicate cached data should never be expired.

    Other Changes

    RTK inlines the TS types for the Redux DevTools Extension options to avoid an extra dependency, but the TS type for the options object wasn't exported publicly. We now export the DevToolsEnhancerOptions type.

    The logic for generating a final URL has been updated to avoid adding an extra trailing /.

    What's Changed

    • Prevent keepUnusedDataFor values from overflowing setTimeout counter by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2595
    • remove typeof undefined checks where not necessary 🐃🪒 by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1726
    • Update RDT options types, and export those + AnyListenerPredicate by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2596
    • Ensures there is no unexpected slash in url before query params by @ygrishajev in https://github.com/reduxjs/redux-toolkit/pull/2470

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.4...v1.8.5

    Source code(tar.gz)
    Source code(zip)
  • v1.8.4(Aug 11, 2022)

    This bugfix release adds exported TS types for RTKQ hooks for use in wrapping logic, adds useDebugValue to the hooks to improve display in the React DevTools, updates the inlined types for the Redux DevTools options, and fixes an issue in createEntityAdapter that could result in duplicate IDs being stored.

    Changelog

    RTKQ Hook Result Types

    RTK's types heavily rely on inference to minimize the amount of type info users have to provide. However, this can also make it difficult to write functions that wrap calls to RTK APIs.

    Some users have asked to have types that help them write "higher-order hooks". RTK now exports types that represent "the return object for a query/mutation hook with a given value": TypedUseQueryHookResult and TypedUseMutationResult. Both require <ResultType, QueryArg, BaseQuery> as generics, like this:

    const baseQuery = fetchBaseQuery({url: "https://some.server"});
    
    type CustomHookResult = TypedUseQueryHookResult<MyResultObject, MyArgObject, typeof baseQuery>
    
    const useMyCustomHook = (arg: MyArgObject) : CustomHookResult => {
      return api.useGetSomeDataQuery(arg);
    }
    

    Redux DevTools Options Fixes

    As of Redux DevTools 3.0, some of field names for custom DevTools options have changed to actionsAllowlist and actionsDenylist. Since we inline the types instead of having a separate dependency, we've updated our TS types to match that. No runtime behavior was changed.

    Other Changes

    RTKQ hooks now use useDebugValue to give a better preview of the current value in the React DevTools "Component" tab.

    The <ApiProvider> component now does a better job of registering and cleaning up focus listeners.

    Fixed a bug with createEntityAdapter that could allow duplicate IDs to be added depending on update parameters.

    What's Changed

    • fix: prevent duplicate ids when updating id of an element with the id of an existing element by @samatar26 in https://github.com/reduxjs/redux-toolkit/pull/2020
    • ApiProvider: correctly register listeners, allow to disable listeners by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/2277
    • Update devtools options TS types based on RDT 3.0 by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2480
    • fix: typo in unhandled error message by @MichielTondeur in https://github.com/reduxjs/redux-toolkit/pull/2538
    • Use useDebugValue in useQuery and useMutation hooks by @kaankeskin in https://github.com/reduxjs/redux-toolkit/pull/2500
    • add types for manually typing hook results in userland code by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2580

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.3...v1.8.4

    Source code(tar.gz)
    Source code(zip)
  • v1.8.3(Jun 30, 2022)

    This bugfix release fixes a few minor issues and bits of behavior, including updating the React-Redux peer dep to ^8.0.2 final, stable sorting in createEntityAdapter.updateMany and some initial state handling in createSlice.

    Changelog

    React-Redux Peer Dep

    We'd previously published an RTK build that accepted React-Redux v8 beta as a peer dep (for use with RTK Query). Since React-Redux v8 is out now, we've updated the peer dep to ^8.0.2.

    Entity Adapter Updates

    Previously, applying updates via createEntityAdapter.updateMany caused sorting order to change. Entities that had the same sorting result should have stayed in the same order relative to each other, but if one of those items had any updates, it would sort to the back of that group. This was due to items being removed from the lookup table and re-added, and since JS engines iterate keys in insertion order, the updated item would now end up compared later than before.

    We've reworked the implementation of updateMany to avoid that. This also ended up fixing another issue where multiple update entries targeting the same item ID would only have the first applied.

    createSlice Initial State

    createSlice now logs an error if initialState is undefined. This is most commonly seen when users misspell initialState. It also has better handling for values that can't be frozen by Immer such as primitives.

    RTK Query

    Several assorted improvements, including TS types for BaseQuery and checking if the body can actually be safely stringified.

    What's Changed

    • Add Missing Else to enhanceEndpoints Function by @kinson in https://github.com/reduxjs/redux-toolkit/pull/2386
    • Check initial state is draftable before using immer to freeze it. by @EskiMojo14 in https://github.com/reduxjs/redux-toolkit/pull/2378
    • Check that body isJsonifiable before stringify by @ShaunDychko in https://github.com/reduxjs/redux-toolkit/pull/2330
    • Respect BaseQuery meta types when enhancing by @TamasSzigeti in https://github.com/reduxjs/redux-toolkit/pull/2225
    • Throw new error when initial state is undefined by @dannielss in https://github.com/reduxjs/redux-toolkit/pull/2461
    • Rewrite updateMany to ensure stable sorting order by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2464
    • Bump React-Redux peer dep by @markerikson in https://github.com/reduxjs/redux-toolkit/commit/3033a33c3dd2ad743f02a44603bc77174599eebc

    New Contributors

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.2...1.8.3

    Source code(tar.gz)
    Source code(zip)
  • v1.8.2(May 25, 2022)

    This bugfix release fixes a minor issue where calling listenerMiddleware.startListening() multiple times with the same effect callback reference would result in multiple entries being added. The correct behavior is that only the first entry is added, and later attempts to add the same effect callback reference just return the existing entry.

    What's Changed

    • Add type @remarks for configureStore's middleware by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2252
    • Fix the "map values transpilation" bug, in yet another place by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2351

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.8.1...v1.8.2

    Source code(tar.gz)
    Source code(zip)
  • v1.8.1(Mar 31, 2022)

    This release updates RTK's peer dependencies to accept React 18 as a valid version. This should fix installation errors caused by NPM's "install all the peer deps and error if they don't match" behavior.

    React-Redux and React 18

    Note: If you are now using React 18, we strongly recommend using the React-Redux v8 beta instead of v7.x!. v8 has been rewritten internally to work correctly with React 18's Concurrent Rendering capabilities. React-Redux v7 will run and generally work okay with existing code, but may have rendering issues if you start using Concurrent Rendering capabilities in your code.

    Now that React 18 is out, we plan to finalize React-Redux v8 and release it live within the next couple weeks. We would really appreciate final feedback on using React-Redux v8 beta with React 18 before we publish the final version.

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0(Feb 27, 2022)

    This release adds the new "listener" middleware, updates configureStore's types to better handle type inference from middleware that override dispatch return values, and updates our TS support matrix to drop support for TS < 4.1.

    Changelog

    New "Listener" Side Effects Middleware

    RTK has integrated the thunk middleware since the beginning. However, thunks are imperative functions, and do not let you run code in response to dispatched actions. That use case has typically been covered with libraries like redux-saga (which handles side effects with "sagas" based on generator functions), redux-observable (which uses RxJS observables), or custom middleware.

    We've added a new "listener" middleware to RTK to cover that use case. The listener middleware is created using createListenerMiddleware(), and lets you define "listener" entries that contain an "effect" callback with additional logic and a way to specify when that callback should run based on dispatched actions or state changes.

    Conceptually, you can think of this as being similar to React's useEffect hook, except that it runs logic in response to Redux store updates instead of component props/state updates.

    The listener middleware is intended to be a lightweight alternative to more widely used Redux async middleware like sagas and observables. While similar to thunks in level of complexity and concept, it can replicate some common saga usage patterns. We believe that the listener middleware can be used to replace most of the remaining use cases for sagas, but with a fraction of the bundle size and a much simpler API.

    Listener effect callbacks have access to dispatch and getState, similar to thunks. The listener also receives a set of async workflow functions like take, condition, pause, fork, and unsubscribe, which allow writing more complex async logic.

    Listeners can be defined statically by calling listenerMiddleware.startListening() during setup, or added and removed dynamically at runtime with special dispatch(addListener()) and dispatch(removeListener()) actions.

    The API reference is available at:

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

    Huge thanks to @FaberVitale for major contributions in refining the middleware API and implementing key functionality.

    Basic usage of the listener middleware looks like:

    import { configureStore, createListenerMiddleware } from '@reduxjs/toolkit'
    
    import todosReducer, {
      todoAdded,
      todoToggled,
      todoDeleted,
    } from '../features/todos/todosSlice'
    
    // Create the middleware instance and methods
    const listenerMiddleware = createListenerMiddleware()
    
    // Add one or more listener entries that look for specific actions.
    // They may contain any sync or async logic, similar to thunks.
    listenerMiddleware.startListening({
      actionCreator: todoAdded,
      effect: async (action, listenerApi) => {
        // Run whatever additional side-effect-y logic you want here
        console.log('Todo added: ', action.payload.text)
    
        // Can cancel other running instances
        listenerApi.cancelActiveListeners()
    
        // Run async logic
        const data = await fetchData()
    
        // Pause until action dispatched or state changed
        if (await listenerApi.condition(matchSomeAction)) {
          // Use the listener API methods to dispatch, get state,
          // unsubscribe the listener, start child tasks, and more
          listenerApi.dispatch(todoAdded('Buy pet food'))
          listenerApi.unsubscribe()
        }
      },
    })
    
    const store = configureStore({
      reducer: {
        todos: todosReducer,
      },
      // Add the listener middleware to the store.
      // NOTE: Since this can receive actions with functions inside,
      // it should go before the serializability check middleware
      middleware: (getDefaultMiddleware) =>
        getDefaultMiddleware().prepend(listenerMiddleware.middleware),
    })
    

    You can use it to write more complex async workflows, including pausing the effect callback until a condition check resolves, and forking "child tasks" to do additional work:

    // Track how many times each message was processed by the loop
    const receivedMessages = {
      a: 0,
      b: 0,
      c: 0,
    }
    
    const eventPollingStarted = createAction('serverPolling/started')
    const eventPollingStopped = createAction('serverPolling/stopped')
    
    listenerMiddleware.startListening({
      actionCreator: eventPollingStarted,
      effect: async (action, listenerApi) => {
        // Only allow one instance of this listener to run at a time
        listenerApi.unsubscribe()
    
        // Start a child job that will infinitely loop receiving messages
        const pollingTask = listenerApi.fork(async (forkApi) => {
          try {
            while (true) {
              // Cancellation-aware pause for a new server message
              const serverEvent = await forkApi.pause(pollForEvent())
              // Process the message. In this case, just count the times we've seen this message.
              if (serverEvent.type in receivedMessages) {
                receivedMessages[
                  serverEvent.type as keyof typeof receivedMessages
                ]++
              }
            }
          } catch (err) {
            if (err instanceof TaskAbortError) {
              // could do something here to track that the task was cancelled
            }
          }
        })
    
        // Wait for the "stop polling" action
        await listenerApi.condition(eventPollingStopped.match)
        pollingTask.cancel()
      },
    })
    

    configureStore Middleware Type Improvements

    Middleware can override the default return value of dispatch. configureStore tries to extract any declared dispatch type overrides from the middleware array, and uses that to alter the type of store.dispatch.

    We identified some cases where the type inference wasn't working well enough, and rewrote the type behavior to be more correct.

    TypeScript Support Matrix Updates

    RTK now requires TS 4.1 or greater to work correctly, and we've dropped 4.0 and earlier from our support matrix.

    Other Changes

    The internal logic for the serializability middleware has been reorganized to allow skipping checks against actions, while still checking values in the state.

    What's Changed

    Since most of the implementation work on the middleware was done over the last few months, this list only contains the most recent PRs since 1.7.2. For details on the original use case discussions and the evolution of the middleware API over time, see:

    PRs since 1.7.2:

    • Rewrite MiddlewareArray and gDM for better Dispatch inference by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2001
    • Change listener middleware API name and signature by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2005
    • feat(alm): add cancellation message to TaskAbortError, listenerApi.signal & forkApi.signal. by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2023
    • [fix][1.8.0-integration][alm]: missing type export by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2026
    • [chore][1.8.0-integration][alm]: apply alm breaking API changes to counter-example by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2025
    • Reorganize serializable check conditions by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/2000
    • fix(alm): prevent zombie listeners caused by forked tasks by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2070
    • Integrate the listener middleware into the RTK package by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2072
    • fix(alm): cancel forkApi.delay and forkApi.pause if listener is cancelled or completed by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2074
    • chore(alm): update counter example to 1.8.0 by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2076
    • Enable cancelling active listeners when unsubscribing by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2078
    • v1.8.0 integration by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2024

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.7.2...v1.8.0

    Source code(tar.gz)
    Source code(zip)
  • v1.8.0-rc.0(Feb 27, 2022)

    This preview release adds the new "listener" middleware, and updates configureStore's types to better handle type inference from middleware that override dispatch return values.

    The full 1.8.0 release will be out shortly (within the next couple days), and this RC is primarily for some final compatibility checking. The final release will have a longer changelog description, with examples.

    Changelog

    New "Listener" Middleware

    We've been working on a new "listener" middleware, which lets you trigger callback functions when specific actions are dispatched or state is changed.

    After iterating on the middleware's API in its own temporary package, it's now ready for actual release as part of RTK.

    The preview API reference is available at:

    https://deploy-preview-2024--redux-starter-kit-docs.netlify.app/api/createListenerMiddleware

    configureStore Middleware Type Improvements

    Middleware can override the default return value of dispatch. configureStore tries to extract any declared dispatch type overrides from the middleware array, and uses that to alter the type of store.dispatch.

    We identified some cases where the type inference wasn't working well enough, and rewrote the type behavior to be more correct.

    TypeScript Support Matrix Updates

    RTK now requires TS 4.1 or greater to work correctly, and we've dropped 4.0 and earlier from our support matrix.

    What's Changed

    • Rewrite MiddlewareArray and gDM for better Dispatch inference by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2001
    • Change listener middleware API name and signature by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2005
    • feat(alm): add cancellation message to TaskAbortError, listenerApi.signal & forkApi.signal. by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2023
    • [fix][1.8.0-integration][alm]: missing type export by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2026
    • [chore][1.8.0-integration][alm]: apply alm breaking API changes to counter-example by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2025
    • fix(alm): prevent zombie listeners caused by forked tasks by @FaberVitale in https://github.com/reduxjs/redux-toolkit/pull/2070
    • Integrate the listener middleware into the RTK package by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2072
    • fix(alm): cancel forkApi.delay and forkApi.pause if listener is cancelled or completed by @markerikson in https://github.com/reduxjs/redux-toolkit/pull/2074

    Full Changelog: https://github.com/reduxjs/redux-toolkit/compare/v1.7.2...v1.8.0-rc.0

    Source code(tar.gz)
    Source code(zip)
  • v1.7.2(Feb 3, 2022)

    This release fixes a TS types bug with RTK Query generated selectors, makes the RTKQ structural sharing behavior configurable, adds an option to have the serializability middleware ignore all actions, and has several minor bugfixes and enhancements to RTK Query.

    Changelog

    RTK Query Selector TS Types Fix

    Several users had reported that as of 1.7.0 selectors generated via apiSlice.endpoint.select() were failing to compile when used, with TS errors that looked like Type '{}' is missing the following properties from type 'CombinedState<>.

    We've fixed the issue, and selectors should now compile correctly when used with TS.

    Additional Configuration Options

    RTK Query implements a technique called "structural sharing" to preserve existing object references if possible when data for an endpoint is re-fetched. RTKQ recurses over both data structures, and if the contents appear to be the same, keeps the existing values. That helps avoid potential unnecessary re-renders in the UI, because otherwise the entire re-fetched result would be new object references.

    However, this update process can potentially take time depending on the size of the response. Endpoints can now be given a structuralSharing option that will turn that off to save on processing time:

        const api = createApi({
          baseQuery: fetchBaseQuery({ baseUrl: "https://example.com" }),
          endpoints: (build) => ({
            getEveryEntityInADatabase: build.query({
              query: () => ({ url: "/i-cant-paginate-data" }),
              structuralSharing: false,
            }),
          }),
        });
    

    Additionally, the serializability check middleware can now be customized with an ignoreActions option to exempt all actions from being checked. This is an escape hatch and isn't recommended for most apps:

        const store = configureStore({
          reducer: rootReducer,
          middleware: (getDefaultMiddleware) =>
            getDefaultMiddleware({
              serializableCheck: {
                ignoreActions: true,
              },
            }),
        });
    

    Other API Improvements

    If an extraArgument was provided to the thunk middleware during store configuration, that value is now passed along to the prepareHeaders() function:

      const store = configureStore({
    	reducer: rootReducer,
    	middleware: (getDefaultMiddleware) =>
    	  getDefaultMiddleware({
    		thunk: {
    		  extraArgument: { myCustomApiService },
    		},
    	  }),
      });
    
      // ..later on
      const api = createApi({
    	baseQuery: fetchBaseQuery({
    	  baseUrl: "https://example.com",
    	  prepareHeaders: async (headers, { getState, extra }) => {
    		const token = getState().auth.token;
    		const somethingElse = await extra.myCustomApiService.someMethod();
    		// do things with somethingElse
    		return headers;
    	  },
    	}),
      });
    

    The invalidatesTags/providesTags functions now receive the action.meta field as an argument, to help with potentially invalidating based on request/response headers.

    Bug Fixes

    refetchOnFocus now cleans up cache entries if a focus event is received and there are no active subscriptions, to avoid unnecessary requests.

    Active polls are cleaned up when the last component for a given subscription unsubscribes.

    The types for builder.addMatcher have been updated to support inference of guards without a type property.

    What's Changed

    • feat(meta): Passes meta to result description functions [#1904] by @bever1337 in https://github.com/reduxjs/redux-toolkit/pull/1910
    • Fix addMatcher typings by @crcarrick in https://github.com/reduxjs/redux-toolkit/pull/1895
    • Pass baseQueryMeta into calculateProvidedBy by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1926
    • Cleanup polls on unsubscribeQueryResult by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1933
    • Add extra to prepareHeaders, update documentation + tests by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1922
    • fix reducerPath for query definitions by @phryneas in https://github.com/reduxjs/redux-toolkit/pull/1977
    • Update serialize documentation link by @wuweiweiwu in https://github.com/reduxjs/redux-toolkit/pull/1983
    • Refetch should not happen if no active subscribers by @AlexanderArvidsson in https://github.com/reduxjs/redux-toolkit/pull/1974
    • Add ignoreActions flag to serializable state middleware by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1984
    • RTKQ: configurable structuralSharing on endpoints/queries/createApi by @msutkowski in https://github.com/reduxjs/redux-toolkit/pull/1954

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

    Source code(tar.gz)
    Source code(zip)
  • 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/toolkit@latest
    
    yarn add @reduxjs/toolkit@latest
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@latest
    
    yarn add @reduxjs/toolkit@latest
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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/toolkit@next.

    Installation:

    npm i @reduxjs/toolkit@next
    
    yarn add @reduxjs/toolkit@next
    

    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)
Owner
Redux
Redux is a predictable state container for JavaScript apps.
Redux
Opinionated SvelteKit Template for building web applications.

Opinionated SvelteKit Template for building web applications.

Manassarn 7 Jan 1, 2023
A highly opinionated and complete starter for Next.js projects ready to production

The aim for this starter is to give you a starting point with everything ready to work and launch to production. Web Vitals with 100% by default. Folder structure ready. Tooling ready. SEO ready. SSR ready.

Fukuro Studio 28 Nov 27, 2022
React + Redux starter kit / boilerplate with Babel, hot reloading, testing, linting and a working example app built in

A comprehensive starter kit for rapid application development using React. Why Slingshot? One command to get started - Type npm start to start develop

Cory House 9.8k Jan 3, 2023
IDE and toolkit for building scalable web applications with React, Redux and React-router

An all-in-one solution for creating modern React apps Rekit is a toolkit for building scalable web applications with React, Redux and React-router. It

Rekit 4.5k Jan 2, 2023
Next Boilerplate with TypeScript, Redux Toolkit and Styled-Component.. For now

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

Ibrahim Yaacob 2 Feb 17, 2022
The next small thing in web development, powered by Svelte

sapper The next small thing in web development, powered by Svelte. What is Sapper? Sapper is a framework for building high-performance universal web a

Svelte 7.1k Jan 2, 2023
No BS webpack development tool for Shopify themes (online store 2.0)

Shopify Theme Development Tool Development tool for Shopify to create themes for Online Store 2.0. Shopify Theme Development Tool Getting Started Comm

null 6 Oct 14, 2021
Next.js + Tailwind CSS + TypeScript starter packed with useful development features

?? ts-nextjs-tailwind-starter Next.js + Tailwind CSS + TypeScript starter packed with useful development features. Made by Theodorus Clarence Features

Cornelius Denninger 7 Nov 12, 2022
Postgres Node.js Express TypeScript application boilerplate with best practices for API development.

Node TypeScript Boilerplate Postgres Developer Ready: A comprehensive template. Works out of the box for most Node.js projects. This project is intend

Chirag Mehta 9 Aug 28, 2022
A boilerplate for REST API Development with Node.js, Express, and MongoDB using TypesScript

node-mongo-boilerplate A simple boilerplate for NODEJS, EXPRESS and MONGODB REST API development . Quick Start Make sure you have node.js v14 + npm v8

Asamoah Michael 5 Oct 16, 2022
Localtunnel module for Nuxt to allow remote/external access to your Nuxt development server.

Nuxt Localtunnel A Nuxt module for automatically running localtunnnel to externally expose your development instance of Nuxt to the outside world. All

null 14 Sep 7, 2022
Oso is a batteries-included library for building authorization in your application.

Oso What is Oso? Oso is a batteries-included library for building authorization in your application. Oso gives you a mental model and an authorization

Oso 2.8k Jan 1, 2023
Batteries-included, zero-config Ionic integration for Nuxt

Nuxt Ionic Ionic integration for Nuxt ✨ Changelog ?? Read the documentation ▶️ Online playground Features ⚠️ nuxt-ionic is currently a work in progres

Daniel Roe 211 Dec 28, 2022
A solid create-remix app, that applies best practices into a clean, batteries included template. SQLite version. Deploys to Fly.io

Remix Barebones Stack npx create-remix --template dev-xo/barebones-stack A solid create-remix app, that follows community guidelines and applies best

Dev XO 97 Dec 30, 2022
⚡️The Fullstack React Framework — built on Next.js

The Fullstack React Framework "Zero-API" Data Layer — Built on Next.js — Inspired by Ruby on Rails Read the Documentation “Zero-API” data layer lets y

⚡️Blitz 12.5k Jan 4, 2023
🚀 Battle-tested Next.js TypeScript Prisma template with an opinionated architecture. 🔋 Included ™️

?? The Ultimate Next.js Starter Pack Next.js ^12 + TypeScript + Prisma + Chakra UI starter packed with useful development features. I've adopted indus

Nam 7 Dec 10, 2022
Grupprojekt för kurserna 'Javascript med Ramverk' och 'Agil Utveckling'

JavaScript-med-Ramverk-Laboration-3 Grupprojektet för kurserna Javascript med Ramverk och Agil Utveckling. Utvecklingsguide För information om hur utv

Svante Jonsson IT-Högskolan 3 May 18, 2022
A fixed-width file format toolset with streaming support and flexible options.

fixed-width A fixed-width file format toolset with streaming support and flexible options. Features Flexible: lot of options Zero dependencies: small

Evologi Srl 6 Jul 14, 2022
Hemsida för personer i Sverige som kan och vill erbjuda boende till människor på flykt

Getting Started with Create React App This project was bootstrapped with Create React App. Available Scripts In the project directory, you can run: np

null 4 May 3, 2022
Kurs-repo för kursen Webbserver och Databaser

Webbserver och databaser This repository is meant for CME students to access exercises and codealongs that happen throughout the course. I hope you wi

null 14 Jan 3, 2023