graphql-zeus
graphql-zeus copied to clipboard
Passing variables to react-query query/mutations does not seem to work
export const useLogin = () =>
useTypedMutation('mutation', {
signIn: [
{
input: {
email: $('email', 'String!'),
password: $('password', 'String!'),
},
},
{ token: true },
],
});
const mutation = useLogin();
mutation.mutate(
{ email: 'asdf', password: 'sdf' }
);
Is there a specific syntax to pass the variables similar to apollo-graphql (using typed-document-node) ? I tried that, but I ran into some other issues.
I was wondering if the syntax is wrong. I even tried:
mutation.mutate(
{ variables: {email: 'asdf', password: 'sdf' } }
);
No luck. Can someone please help or guide on using react-query with graphql-zeus or should I fallback to apollo/client.
Hi @vysakh0 I also encountered the same problem, I think the problem is within the generated useTypedMutation function:
return useMutation<TResult>(mutationKey, () => Chain(HOST, hostOptions)("mutation")(mutation) as Promise<TResult>)
It's a little bit different from the example of react-query useMutation
I don't know why Zeus generates the code that way, but I am able to run the mutation like this:
CustomHook:
export const useLogin = (email, password) =>
useTypedMutation('mutation', {
signIn: [
{
input: {
email,
password
},
},
{ token: true },
],
});
Inside Component:
const mutation = useLogin('yourEmail', 'yourPassword);
mutation.mutate();
console.log(mutation.data.signIn) // autocomplete works
@zelief Thank you for the reply. In component we can't use like this right? Typically these are form and we only send the params on submission. We can pass the params to custom hook if we know the params during initial render, I need to send the params to .mutate function on form submission.
Yes, we can't use like that, so I use state for the parameters, something like this:
const [email, setEmail ] = useState('');
const [pwd, setPwd ] = useState('');
const mutation = useLogin(email, pwd);
And add onChange in the input components. If you use React Hook Form it will be much easier using watch, we don't need to handle input change, we can do it like this:
const { watch } = useForm();
const loginMutation = useLoginMutation(watch("email"), watch("password"));
I am now experimenting with a variation on the react-query bindings spliced up with a bit of the Apollo bindings. It goes something like this, although I expect I'll need to tweak it more later.
export function useTypedQuery<O extends "Query", TData extends ValueTypes[O], TResult = InputType<GraphQLTypes[O], TData>>(
queryKey: QueryKey,
query: TData | ValueTypes[O],
options?: Omit<UseQueryOptions<TResult, any, any>, 'queryKey' | 'queryFn'>,
graphqlOptions?: {
variables: Record<string, unknown>;
operationOptions?: OperationOptions;
scalars?: ScalarDefinition;
host: string;
hostOptions: chainOptions[1];
},
) {
return useQuery<TResult, any, any>(queryKey, () => Chain(
graphqlOptions?.host || '/graphql',
graphqlOptions?.hostOptions || {}
)("query")(query, {
variables: graphqlOptions?.variables || {},
operationName: typeof queryKey === 'string' ? queryKey : queryKey.join('_'),
}) as Promise<TResult>, options);
}
I was going really deep on this yesterday, because I wanted to be able to do the following:
const registerForEventMutation = useArkiveMutation({
registerForEvent: {
status: true,
},
});
//
//--- Handlers
//
const handleRegisterForEvent = (eventId: number) => {
registerForEventMutation.mutate(
{ registerForEvent: { eventId } }
);
};
Which I managed to get to with the following (probably too complex) hook:
type MutationKeys = keyof Omit<
ValueTypes["RootMutationType"],
"__typename" | "__alias" | "__directives"
>;
type Mutations = Pick<ValueTypes["RootMutationType"], MutationKeys>;
type ValueOf<T> = T[keyof T];
type MapObjectToVariables<PropType> = PropType extends NonNullable<
ValueOf<Mutations>
>
? PropType[0]
: PropType;
type MapToObjectReturnType<PropType> = PropType extends NonNullable<
ValueOf<Mutations>
>
? PropType[1]
: PropType;
type MutationVariableRecord<T extends Mutations> = {
[Key in keyof T]: MapObjectToVariables<T[Key]>;
};
type MutationSelectorRecord<T extends Mutations> = {
[PropertyKey in keyof T]: MapToObjectReturnType<T[PropertyKey]>;
};
const mapToMutation = <
TData extends Mutations,
TModel extends MutationSelectorRecord<TData>,
TVariables extends MutationVariableRecord<TData>
>(
model: TModel,
vars: TVariables
) => {
return Object.keys(model).reduce(
(acc, key) => ({
...acc,
[key]: [vars[key as keyof typeof vars], model[key as keyof typeof model]],
}),
{}
);
};
export const useArkiveMutation = <
TData extends Mutations,
TModel extends MutationSelectorRecord<TData>,
TKeys extends Extract<keyof TData, keyof TModel>,
TVariables extends Required<Pick<MutationVariableRecord<TData>, TKeys>> & {
variables?: Record<string, unknown>;
},
TResult extends InputType<GraphQLTypes["RootMutationType"], TModel>
>(
model: TModel,
options?: Omit<
UseMutationOptions<TResult, any, TVariables>,
"mutationKey" | "mutationFn"
>
) => {
return useMutation<TResult, unknown, TVariables>(
({ variables, ...rest }) =>
arkiveClient("mutation")(mapToMutation(model, rest), {
variables,
}) as Promise<TResult>,
options
);
};