Skip to content

Releases: reduxjs/redux-toolkit

v1.8.0

27 Feb 20:57
Compare
Choose a tag to compare

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:

Full Changelog: v1.7.2...v1.8.0

v1.8.0-rc.0

27 Feb 02:49
Compare
Choose a tag to compare
v1.8.0-rc.0 Pre-release
Pre-release

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 #2001
  • Change listener middleware API name and signature by @markerikson in #2005
  • feat(alm): add cancellation message to TaskAbortError, listenerApi.signal & forkApi.signal. by @FaberVitale in #2023
  • [fix][1.8.0-integration][alm]: missing type export by @FaberVitale in #2026
  • [chore][1.8.0-integration][alm]: apply alm breaking API changes to counter-example by @FaberVitale in #2025
  • fix(alm): prevent zombie listeners caused by forked tasks by @FaberVitale in #2070
  • Integrate the listener middleware into the RTK package by @markerikson in #2072
  • fix(alm): cancel forkApi.delay and forkApi.pause if listener is cancelled or completed by @markerikson in #2074

Full Changelog: v1.7.2...v1.8.0-rc.0

v1.7.2

03 Feb 03:35
Compare
Choose a tag to compare

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

Full Changelog: v1.7.1...v1.7.2

v1.7.1

16 Dec 03:52
53f56a4
Compare
Choose a tag to compare

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

What's Changed

Full Changelog: v1.7.0...v1.7.1

v1.7.0

10 Dec 19:22
Compare
Choose a tag to compare

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:

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 co...

Read more

v1.7.0-rc.0

01 Dec 16:34
Compare
Choose a tag to compare
v1.7.0-rc.0 Pre-release
Pre-release

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 #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: v1.7.0-beta.1...v1.7.0-rc.0

v1.7.0-beta.1

05 Nov 02:07
Compare
Choose a tag to compare
v1.7.0-beta.1 Pre-release
Pre-release

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

Full Changelog: v1.7.0-beta.0...v1.7.0-beta.1

v1.7.0-beta.0

29 Oct 19:15
5e36d3a
Compare
Choose a tag to compare
v1.7.0-beta.0 Pre-release
Pre-release

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:

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:

What's Changed

Full Changelog: v1.6.2...v1.7.0-beta.0

v1.6.2

05 Oct 02:15
Compare
Choose a tag to compare

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

Full Changelog: v1.6.1...v1.6.2

v1.6.1

17 Jul 23:47
Compare
Choose a tag to compare

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