Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { Draft } from 'immer';
- import {
- DefinitionsFromApi,
- InfiniteData,
- InfiniteQueryArgFrom,
- InfiniteQueryDefinition,
- MutationDefinition,
- PageParamFrom,
- QueryArgFrom,
- QueryDefinition,
- ResultTypeFrom,
- TypedMutationOnQueryStarted,
- } from '@reduxjs/toolkit/query';
- import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react';
- interface Model {
- id: number;
- type: 'model';
- flibbertygibbits: number;
- }
- interface Other {
- id: number;
- type: 'other';
- foobars: number;
- }
- const baseApi = createApi({
- baseQuery: fetchBaseQuery(),
- endpoints: build => ({
- models: build.query<Model[], { id?: number } | void>({
- query: ({ id } = {}) => `models/${id != null ? `${id}/` : ''}`,
- }),
- // allModels: build.infiniteQuery<Model[], { id?: number } | void, number>({
- // query: ({ queryArg: { id } = {}, pageParam }) => `models/${id != null ? `${id}/` : ''}`,
- // infiniteQueryOptions: {
- // initialPageParam: 1,
- // getNextPageParam: (lastPage, allPages, lastPageParam, allPageParams) => lastPageParam + 1,
- // },
- // }),
- mutateModel: build.mutation<Model, { id: number; flibberygibbits: number }>({
- query: ({ id }) => `models/${id}`,
- }),
- // others: build.query<Other[], { id?: number } | void>({
- // query: ({ id } = {}) => `others/${id != null ? `${id}/` : ''}`,
- // }),
- // mutateOther: build.mutation<Other, { id: number; foobars: number }>({
- // query: ({ id }) => `others/${id}`,
- // }),
- }),
- });
- type ApiEndpointDefinitions = DefinitionsFromApi<typeof baseApi>;
- type ApiQueryEndpoints = {
- [K in keyof ApiEndpointDefinitions as ApiEndpointDefinitions[K] extends QueryDefinition<any, any, any, any>
- ? K
- : never]: ApiEndpointDefinitions[K];
- };
- type ApiInfiniteQueryEndpoints = {
- [K in keyof ApiEndpointDefinitions as ApiEndpointDefinitions[K] extends InfiniteQueryDefinition<
- any,
- any,
- any,
- any,
- any
- >
- ? K
- : never]: ApiEndpointDefinitions[K];
- };
- type ApiMutationEndpoints = {
- [K in keyof ApiEndpointDefinitions as ApiEndpointDefinitions[K] extends MutationDefinition<any, any, any, any>
- ? K
- : never]: ApiEndpointDefinitions[K];
- };
- function optimisticMutation<
- const K extends keyof ApiQueryEndpoints | keyof ApiInfiniteQueryEndpoints,
- const MK extends keyof ApiMutationEndpoints,
- >(k: K, mk: MK) {
- type OriginalArgs = K extends keyof ApiQueryEndpoints
- ? QueryArgFrom<ApiEndpointDefinitions[K]>
- : K extends keyof ApiInfiniteQueryEndpoints
- ? InfiniteQueryArgFrom<ApiEndpointDefinitions[K]>
- : never;
- type MutationArgs = QueryArgFrom<ApiEndpointDefinitions[MK]>;
- type QueryData = K extends keyof ApiQueryEndpoints
- ? ResultTypeFrom<ApiEndpointDefinitions[K]>
- : K extends keyof ApiInfiniteQueryEndpoints
- ? InfiniteData<ResultTypeFrom<ApiEndpointDefinitions[K]>, PageParamFrom<ApiEndpointDefinitions[K]>>
- : never;
- type MutationData = ResultTypeFrom<ApiEndpointDefinitions[MK]>;
- type Recipe = (draftData: QueryData | Draft<QueryData>) => void | QueryData | Draft<QueryData>;
- return (
- optimistic: (originalArgs: OriginalArgs, mutationArgs: MutationArgs) => Recipe,
- pessimistic?: (originalArgs: OriginalArgs, mutationArgs: MutationArgs, data: MutationData) => Recipe,
- ): NonNullable<TypedMutationOnQueryStarted<MutationData, MutationArgs, ReturnType<typeof fetchBaseQuery>>> => {
- return async (mutationArgs, api) => {
- const undo = baseApi.util
- .selectCachedArgsForQuery(api.getState(), k)
- .map(
- originalArgs =>
- api.dispatch(baseApi.util.updateQueryData(k, originalArgs, optimistic(originalArgs, mutationArgs))).undo,
- );
- try {
- const { data: result } = await api.queryFulfilled;
- if (pessimistic) {
- baseApi.util
- .selectCachedArgsForQuery(api.getState(), k)
- .forEach(originalArgs =>
- api.dispatch(
- baseApi.util.updateQueryData(k, originalArgs, pessimistic(originalArgs, mutationArgs, result)),
- ),
- );
- }
- } catch {
- undo.forEach(u => u());
- // nothing
- }
- };
- };
- }
- export const enhancedApi = baseApi.enhanceEndpoints({
- endpoints: {
- mutateModel: {
- onQueryStarted: optimisticMutation('models', 'mutateModel')(
- (originalArgs, mutationArgs) => drafts => {
- const i = drafts.findIndex(d => d.id === mutationArgs.id);
- if (i !== -1) {
- // optimistic update based on client mutation
- drafts[i].flibbertygibbits = mutationArgs.flibberygibbits;
- }
- },
- (originalArgs, mutationArgs, data) => drafts => {
- const i = drafts.findIndex(d => d.id === mutationArgs.id);
- if (i !== -1) {
- // pessimistic update based on server response
- drafts[i] = { ...drafts[i], ...data };
- }
- },
- ),
- },
- },
- });
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement