T
TanStack3mo ago
correct-apricot

Using useQuery result in custom hook

Hi, I'm having trouble using the result of a query in a custom hook, as the hook runs before the promise is resolved, resulting in passing it an undefined object. My query looks something like this:
const {data: formResponse, isLoading} = useQuery<DynamicForm>({
queryKey: ['form', formId],
queryFn: async () => {
try {
const form = await getFormById(Number(formId));
const parsedForm = parseForm(form.data ?? ({} as DynamicFormDto));
return parsedForm;
} catch (err) {
console.error('Error in form query:', err);
throw err;
}
},
retry: false,
});
const {data: formResponse, isLoading} = useQuery<DynamicForm>({
queryKey: ['form', formId],
queryFn: async () => {
try {
const form = await getFormById(Number(formId));
const parsedForm = parseForm(form.data ?? ({} as DynamicFormDto));
return parsedForm;
} catch (err) {
console.error('Error in form query:', err);
throw err;
}
},
retry: false,
});
and then i just want to use it like this:
const {state, actions} = useForm(formResponse);
const {state, actions} = useForm(formResponse);
formResponse gets passed as undefined, which the compilers warns about, but I don't know how i can narrow it down to the supposed type, since we can't call hooks conditionally. Any help is very much appreciated, thank you.
6 Replies
unwilling-turquoise
unwilling-turquoise3mo ago
const {state, actions} = useForm(formResponse ?? {});
const {state, actions} = useForm(formResponse ?? {});
Would something like this not work?
sensitive-blue
sensitive-blue3mo ago
Maybe try to separate the component? We could have component A thats responsible to fetch the data. And component B that handle the data after the fetch is complete
other-emerald
other-emerald3mo ago
If you want to prevent your queryFn from running until the value is defined, you can either A. use the enabled option to set the query to disabled until the value is defined B. Return a skipToken from your queryFn when the value is undefined
foreign-sapphire
foreign-sapphire3mo ago
It's not a trivial task. Usually, most of the form libraries have some flag like enableReinitialize which allows them to reset initial values from undefined to the expected values if they come from a promise. The other approach would be to make your custom useForm hook to await for the values to be defined, with the enabled flag like they do in useQuery or something similar. useForm hook will still run, but it will not set up values until they are defined. You can not narrow the state down to only an expected type. It will be ExpectedType | undefined because your useQuery hook may fail, and then you will not get any response. So you need to consider this. What you should do is to narrow this state before you use it with something like this:
if(!state) return null;

OR

{state && (
<SomeComponent state={state} /> // <-- here your state will be always of ExpectedType
)}
if(!state) return null;

OR

{state && (
<SomeComponent state={state} /> // <-- here your state will be always of ExpectedType
)}
foreign-sapphire
foreign-sapphire3mo ago
React Query and Forms
Forms tend to blur the line between server and client state, so let's see how that plays together with React Query.
correct-apricot
correct-apricotOP3mo ago
This works and is what i add before, but i had to move the state up, and so this solution would result in a ghost component this works and is what i ended up with, but had to make changes to the hook for it to handle empty objects properly

Did you find this page helpful?