I'm building a form (based on react-hook-form) to filter a list of events by start and end date. The list is retrieved with react-query's useQuery()
call. There's a zod-based validation in place (via @hookform/resolvers) to make sure the end date always comes after the start date.
I tried various approaches but none of them really worked the way I expected (my examples use tRPC, but this shouldn't change things):
1. Introduce a dedicated state for the query which gets set in the onSubmit()
handler.
const [query, setQuery] = useState({ startDate: initialStartDate, endDate: initialEndDate });
const { handleSubmit } = useForm({
mode: 'onChange',
schema: myValidationSchema,
});
const events = trpc.bookings.events.useQuery(query, {
keepPreviousData: true
});
return (
<form onSubmit={handleSubmit((values) => { setQuery(values) })}>
...
</form>
)
This almost works, but it's somewhat weird that the query is automatically run when the component mounts. Also, what if there is no initial default state which satisfies the query? Imagine I don't want to default to a startDate
and endDate
but leave this for the user to fill out before running the query? {}
does not satisfy the query constraints because startDate
and endDate
are required.
2. Get rid of the submit button and watch the form for changes. Then use the current form fields as the query payload.
I couldn't get this to work with the form validation. Queries were run although the form was in an invalid state.
const { watch } = useForm({
mode: 'onChange',
schema: myValidationSchema,
});
const query = watch();
const events = trpc.bookings.events.useQuery(query, {
keepPreviousData: true,
});
I tried adding enabled: formState.isValid
to the useQuery()
options, but isValid
does not represent the state of the validation accurately (probably due to its reactive nature). When logging it to the console, I can see it flapping between true
and false
in short succession when changing fields. The truthy state triggers the query with invalid values, which is what I'm trying to prevent in the first place.
3. Set enabled: false
and refetch()
in the onSubmit()
handler.
This has the same drawback as the first two approaches: The query needs an initial state (which I might not have). Also, changing options in the form automatically updates the list of results when they have been fetched beforehand (because they're served from react-query's cache).
4. useMutation
instead of useQuery
This would probably work best because it's easy to programmatically trigger the request with validated data from the form in the onSubmit()
handler, but I haven't even tried it, because it just feels so wrong to use a POST
request when a GET
request is clearly the way to go here.
I feel like I must be doing something terribly wrong here, because the task is so common (filter a list of things by valid values from a form) and react-query is giving me such a hard time.