Wrapping RTKQ Hooks (and getting the typing right) #1471
Replies: 4 comments 5 replies
-
@StefanBRas did you get anywhere with this in the end? |
Beta Was this translation helpful? Give feedback.
-
I was trying to do something similar by wrapping the query hooks so I can add some common behaviour. The problem for me remains the same - cannot get the typing right so that I dont lose the BE payload type. My code is something along those lines: import React from 'react';
import { NotificationManager } from '@styleguide/composite/notifications';
import { UseMutation } from '@reduxjs/toolkit/dist/query/react/buildHooks';
import { MutationDefinition } from '@reduxjs/toolkit/dist/query';
const useGenericNotification = <T extends UseMutation<MutationDefinition<any, any, string, any, string>>>(
mutation: T,
{ notification = 'Success' } = {}
) => {
const [mutate, status] = mutation();
const mutateWithNotification = React.useCallback(
async (data) => {
try {
const response = await mutate(data).unwrap();
NotificationManager.success(notification);
return response;
} catch (error) {
NotificationManager.error(error.toString());
throw error;
}
},
[mutate, notification]
);
return [mutateWithNotification, status] as const;
};
export { useGenericNotification }; Ideas are welcome ; ) |
Beta Was this translation helpful? Give feedback.
-
Hi, not sure if anyone is still interested in this, but the following works perfectly for me: import { BaseQueryFn, MutationDefinition } from '@reduxjs/toolkit/query';
import { UseMutation } from '@reduxjs/toolkit/dist/query/react/buildHooks';
const useWrappedMutation = <U, V extends BaseQueryFn, W>(
mutation: UseMutation<MutationDefinition<U, V, string, W>>
): ReturnType<UseMutation<MutationDefinition<U, V, string, W>>> => {
const [mutate, status] = mutation();
// Do your think with the mutation/status ...
return [mutate, status];
}; |
Beta Was this translation helpful? Give feedback.
-
here is the helper, in case you need to have a small/nice code to skip when some of arguments is undefined: // utils to put somewhere separately:
const undefinedFilter = ((v: any) => typeof v !== 'undefined') as any as <T>(
x: T | undefined,
) => x is NonNullable<T>;
function allFieldsDefined<O extends Record<string, any>>(o: O): o is PropsNonNullable<O> {
return Object.values(o).every(undefinedFilter);
}
// main utility
import { skipToken } from '@reduxjs/toolkit/query/react';
function paramsOrSkip<P>(p: Partial<P>): P | typeof skipToken {
return allFieldsDefined(p) ? p : skipToken;
}
// your cool hook with required param inside (projectId in this example), fed with another hook that can return undefined;
// our RTK query will be skipped while any of arguments is undefined
export function useFetchSomethingQuery() {
return api.useFetchSomethingQuery(
paramsOrSkip({ // params infer from the query which is cool
projectId: useProjectId(), // no conditional call here, so you may invoke hooks directly without defining constants
somethingElse: useSomethingElse(),
}),
);
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
TLDR; I want to make a generic wrapper around RTKQ hooks, but when i try to pass the
options
argument to the wrapped hook, it breaks the typing. See the codebox and notice theoptionsData
has typeany
, while the others correctly infers the type.Hello!
I'm using RTK Query. Most of my hooks use some value from my redux store, and some use several. To avoid having to use useSelectors everytime i use these useQuery hooks, I can either
args
being passed or,Now, if I do 1 i have to manually invalidate the cache whenever the value from the store changes, so i want to go with 2.
This is easy enough, for example (omitting redux stuff just for clarity):
I'm ignoring the
options
parameter for now.This works but requires me to do it with every hook. So i make a generic wrapper, that takes the name of the endpoint and the name of arguments which is given in the wrapper (and thus removed from the inner hooks' arguments).
I use some type helper too, you can see them here:
Typing helpers
Generic version:
This works great and if i use the
useGetStuffQueryWrappedBasic
hook in a component, theargs
are correctly inferred to be only{args2: string}
now. Nice! So I want the wrapped hook to pass the options to the inner hook so i do:but whenever I try to use this wrapper, the
data
will come out asany
even though the only difference is adding theoptions
.I have solved this for now by making an assertion so i instead return
But of course I'd rather avoid this assertion if possible.
I'd love to hear your thoughts on this and you can try this codesandbox to play around with it.
Beta Was this translation helpful? Give feedback.
All reactions