An utility component for @tanstack/react-query that simplifies types and query state narrowing inside [nested] JSX.
npm install switch-query
# or
yarn add switch-query
Supported React Query versions are v5
and v4
.
Supported React versions: ^19
, ^18
, ^17
, ^16.8
.
Basic example:
import { useQuery } from '@tanstack/react-query';
import { SwitchQuery } from 'switch-query';
const Example = function Example() {
const query = useQuery({
queryKey: ['foo'],
queryFn: () => Promise.resolve({ value: 42 }),
});
return (
<SwitchQuery
query={query}
pending={<div>loading...</div>}
success={({ data }) => (
<div>
Value is:
{' '}
{data.value}
</div>
)}
error={({ refetch }) => (
<div>
<div>An error occurred</div>
<button type="button" onClick={() => refetch()}>
retry
</button>
</div>
)}
/>
);
};
With error
prop you can use typed defined error in render:
import { useQuery } from '@tanstack/react-query';
import { SwitchQuery } from 'switch-query';
const Example = function Example() {
// or explicit error typing useQuery<unknown, CustomErrorClass>(...)
const query = useQuery({
queryKey: ['foo'],
queryFn: () => Promise.reject(new Error('Test error')),
});
return (
<SwitchQuery
query={query}
error={({ error }) => (
<div>
<h2>An error occurred</h2>
<div>{error.message}</div>
</div>
)}
/>
);
};
Using checkIsEmpty
prop you can separate empty state from successful state:
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import { SwitchQuery } from 'switch-query';
const Example = function Example() {
const [search, setSearch] = useState('');
const query = useQuery({
queryKey: ['foo', search],
queryFn: () => Promise.resolve({
fruits: (['apple', 'banana', 'orange']).filter((fruit) => fruit.includes(search))
}),
});
return (
<div>
<div>
<input
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
{query.isFetching && <span>fetching...</span>}
</div>
<div>
<SwitchQuery
query={query}
checkIsEmpty={(data) => !Array.isArray(data) || !data.length}
pending={<div>Loading</div>}
success={({ data }) => (
<ul>
{data.fruits.map((fruit) => (
<li key={fruit}>
{fruit}
</li>
))}
</ul>
)}
empty={<div>Nothing found</div>}
/>
</div>
</div>
);
};
query
– React Query object returned fromuseQuery
.success
– Success state render function or node.query.data
is defined.pending
– Pending state render function or node. Renders whenquery.status === "pending"
orquery.isPending === true
but not on everyquery.isFetching === true
.error
– Error state render function or node.query.error
is defined and not null.checkIsEmpty
– Optional function to check that defined data in success state is empty to renderempty
prop.empty
– Empty state render function or node. Renders whencheckIsEmpty
returnstrue
.query.data
is defined (but empty).