Releases: rtk-incubator/rtk-query
Beta 0.3
This beta release of RTK Query adds new APIs for working with external service classes in endpoints, adds lazy queries, splits the React-specific functionality into a new /react
entry point, renames the "entity" concept to "tags", and makes a variety of tweaks and fixes for fetching behavior and our TypeScript types.
This is the final planned pre-release for RTK Query as a standalone library. The APIs are effectively finalized at this point, and we're now ready to merge the RTK Query source code and documentation back into the main Redux Toolkit repo. The plan is to release RTK Query as a new pair of entry points ( /query
and /query/react
) in the upcoming Redux Toolkit 1.6 package release. We'll lock this repo once we're ready to switch where issues should be filed.
The APIs are stable enough that you can consider using them in production. We may make a few final tweaks as we merge this back into RTK or get feedback based on this release, but most likely the only migration steps needed from this release to RTK 1.6 would be changing the import paths.
Changelog
New queryFn
Option for Endpoints
The typical approach for making actual API requests is to use the fetchBaseQuery
wrapper included in RTKQ. However, there are times you may want to use a custom function for making the request. This is especially true if you are working with some kind of external API client like a Google API or Firebase wrapper.
We now support supplying a queryFn
option inside of an endpoint definition, in which case that specific endpoint will use the function you provided for fetching data.
If you want to enforce that all endpoints in a given API slice must supply a queryFn
, you can set the API slice to use the fakeBaseQuery
instance instead of fetchBaseQuery
. This will throw an error if actually used to make a request, and also allows you to define a common TS error type for all the queryFn
usages as a generic type arg:
const api = createApi({
baseQuery: fakeBaseQuery<CustomErrorType>(),
endpoints: (build) => ({
withAsyncQueryFn: build.query<string, string>({
async queryFn(arg: string) {
return { data: `resultFrom(${arg})` };
},
}),
})
});
Lazy Queries
We now have a useLazyQuery
hook, which lets you delay actually fetching data until you call the trigger function supplied by the hook:
const [fetchThing, { data, isLoading, ...rest }] = api.endpoints.getPosts.useLazyQuery({
refetchOnFocus,
refetchOnReconnect,
pollingInterval
});
<button onClick={() => fetchThing({ with: 'variable', another: 'one' })}>Do a fetch</button>
New Utility Functions
RTK Query typically manages invalidation of data and clearing out internal state, but there are times you may wish to trigger that functionality yourself. API slices now include an additional pair of thunk functions under the utils
key, invalidateTags
and resetApiState
. You can manually dispatch those thunks yourself if needed.
selectFromResult
for Mutations
The useMutation
hook now accepts a selectFromResult
option similar to useQuery
. This allows a user to 'optimize renders' by only rerendering when the selected values change. There will always be 1 rerender when the mutation is called as it creates a new requestId. An example of optimizing this behavior might look like yourEndpoint.useMutation(undefined, { selectFromResult: () => ({}) })
.
Breaking Changes
New React-Specific Entry Point
Redux Toolkit has always been UI-agnostic, and the majority of RTK Query is UI-agnostic as well. In order to keep that core UI-agnostic, we've moved the React-specific functionality into a new /react
entry point. That entry point exports everything from the root entry point, but the React-specific version of createApi
will also auto-generate React hooks for the endpoints.
If you are using RTK Query with React, you'll need to change your imports to:
import { createApi } from "@rtk-incubator/rtk-query/react";
Note that when we move RTK Query over into Redux Toolkit itself, we expect the final entry points to be:
import { createSlice} from "@reduxjs/toolkit";
import { createApi as genericCreateApi } from "@reduxjs/toolkit/query";
import { createApi as reactCreateApi } from "@reduxjs/toolkit/query/react";
We recognize that the entry point paths are a bit lengthy, but we expect that most applications will only need to have these imports in a handful of API slice definition files.
API and Type Renaming
We've gone through the API definitions and done a (hopefully final) round of renaming and cleanup. In particular, we've renamed the "entity" concept that is used for cache invalidation to "tags" instead, which also applies to several specific field names:
entity
->tag
entityTypes
->tagTypes
provides
->providesTags
invalidates
->invalidatesTags
We've also renamed the utils.prefetchThunk
function in API slice objects to utils.prefetch
for consistency, renamed the endpoint
field in hook status objects to endpointName
, and removed the internalQueryArgs
field.
If you are using any of these fields and want some help renaming your code to match, we have an initial v2-v3
codemod available at https://github.com/rtk-incubator/rtk-query-codemods . We've also inserted some temporary dev-only warnings if you attempt to use any of the old field names like provides
.
Tag Invalidation Signatures
The signature of providesTags
and invalidatesTags
has changed from (result, arg) => Tags
to (result?, error?, arg) => Tags
, which allows providing and invalidating tags even when a query has errored.
Other Improvements
fetchBaseQuery
now supports FormData
as a body, clears undefined headers, and has better handling for JSON content vs non-JSON Content like FormData
or ArrayBuffer
.
useQueryHooks
now go straight to isLoading
on the first render instead of isUninitialized
to simplify loading state logic, unless the hook is being skipped as it starts.
We've fixed issues related to SSR and React Fast Refresh.
It was possible for selectFromResult
to return a primitive like a number, but that breaks with how the query state results are merged together to form the hook return value. The TS types now enforce that selectFromResult
must return an object, which will be shallow-merged into the hook result value.
Docs Improvements
We've restructured the docs to better document what is part of createApi
, vs what is in the API slice objects generated by createApi
. We've also done a bunch of cleanup and fleshing out of content.
Note that as of right now, not all of the new functionality in this release has been fully documented. We're working on filling out the missing docs content now, and will have a complete set of documentation when RTK 1.6 is ready.
Changes
New APIs
- Add
queryFn
as alternative toquery
to endpoint definitions (#158) @phryneas
enables use with external libraries that provide a service class, such as the spotify api, google apis, firebase or grpc services - as well as chaining multiple requests in one combined "endpoint"
also addsfakeBaseQuery
for apis without anybaseQuery
- Add
utils.invalidateEntities
(#190) @msutkowski - Add
utils.resetApiState
(#189) @msutkowski - Add useLazyQuery (#177) @msutkowski, @phryneas
- Add
selectFromResult
for mutations ( #206 ) @msutkowski
Potentially Breaking
- extra
/react
entrypoint (#141) @phryneas - [minor breaking] remove internalQueryArgs, pass endpointDefinition into serializeQueryArgs, rename endpoint to endpointName or endpointDefinition everywhere (#156)
- Call
providesTags/invalidatesTags
when a query has an isError state (#201) @phryneas - last minute renames (#213) @phryneas
Tweaks and Fixes
- Support FormData in fetchBaseQuery (#140) @msutkowski
- Clear undefined values from headers (#146) @kahirokunn
- Export FetchBaseQueryArgs (#145) @kahirokunn
- SSR Support: delete substate.error property (#152) @gfortaine
- TypeScript: Loosen dispatch types (#150) @kahirokunn
- fetchBaseQuery: Fix: JSON.stringify body when it isJsonifiable and content-type is 'application/json' (#168) @gfortaine
- Reset promiseRef on useQuery/Mutation hooks on unmount (#173) @msutkowski
- useQuery: skip
uninitialized
status (#197) @phryneas - Enforce an object return from
selectFromResult
(#216) @markerikson
Alpha 2
This release brings query result selectors (with structural sharing), code generation, a module system and lots of other improvements and updates to the still-WIP APIs.
Changes
selectFromResult
option for useQuery
We've had some discussion & requests around the possibility to just subscribe to part of a query result instead of the full result and isFetching
/isSuccess
/etc., to have more granular rerenders.
This is now possible with the selectFromResult
option to useQuery
.
One thing that we had to add to make this possible is "structural sharing".
So, if you have a second request that comes back with (partially) similar data, we try to recycle as many object references from the last query result as possible, to prevent unneccessary rerender.
If you want to only select query result data or only trigger a query without caring for any result, you can now use the useQueryState
and useQuerySubscription
hooks. (#106)
Code generation
Another big thing is code generation. You can now generate full API definitions from OpenAPI definitions. Big thanks to @fgnass who let us use the type generation from his oazapfts
library.
If you want to give it a try, run curl -o petstore.json https://petstore3.swagger.io/api/v3/openapi.json; npx @rtk-incubator/rtk-query-codegen-openapi petstore.json > petstore-api.generated.ts
.
Docs are over at https://rtk-query-docs.netlify.app/concepts/code-generation
Modularization & new build
The third big thing is a new build configuration to enable tree-shaking. Bundle sizes are significantly down due to that. Also, RTK-Query has been modularized, so you can now use createBaseApi
if you don't need the React hooks
The module system also allows you to write your own createApi
plugins. See https://rtk-query-docs.netlify.app/concepts/customizing-create-api
More granular hooks refetch behaviour
In addition, we've added some new options to tweak the refetch behaviour of the hooks.
There now are refetchOnFocus
and refetchOnReconnect
options for the hooks. (#90)
Also, we now have a refetchOnMountOrArgChange
option to trigger a refetch when a component is mounted/changes its query argument even if there is already data in the cache for the target route. You can specify a "minumum age" here. (#80)
Other changes
-
We had a bug report & fix PR from https://twitter.com/PettengillAaron for the edge case when an api returned an empty response body. Parsing that as JSON was probably not a good idea. Thanks! (#91)
-
You can now pass in a custom
fetch
function intofetchBaseQuery
- this came up in a discussion on server side rendering as a way to make better use offetch
ponyfills. Thanks to https://twitter.com/JoshMarantz for bringing this up. (#105) -
You can now call
.unwrap
on the result from theuseMutation
hook andmutation.initiate
action creator to have the promise resolve with the returned value or throw an exception. If people like this API, we might add this to RTKscreateAsncThunk
as an alternative tounwrapResult
. Thanks for https://twitter.com/kahirokunn for bringing this up. (#117)
Also, be aware: this changed the general return value of the result from theuseMutation
hook from the resulting state to{data: ...} | {error: ...}
in case you're not unwrapping. -
prepareHeaders
can now be an async function. Thanks to https://github.com/schadenn for the contribution. (#123) -
Query endpoint definitions now support the same
onStart
,onError
andonSuccess
options that mutation endpoints already did. Thanks to https://twitter.com/kahirokunn. (#130) -
api.internalActions.prefetchThunk
was renamed toapi.util.prefetchThunk
(#133)
A big thanks to everyone I forgot to mention here who discussed with us on github, in @reactiflux, or here on Twitter.
And an enormous "thank you" to https://twitter.com/de_stroy who did an incredible amount of PRs, Code Reviews and Documentation.
v0.1.0
Initial release!