not to make things too simple, but my code goes like this -
const Component = () => {
const { data } = useLoaderData();
const [searchParams, setSearchParams] = useSearchParams();
const handleClick = () => {
searchParams.set('page', parseInt(searchParams.get('page')) + 1);
setSearchParams(searchParams);
}
return(
<>
<Suspense fallback={ <>Loading</> }>
<Await resolve={data}>
{ (data) => <>data</> }
</Await>
</Suspense>
<button onClick={ () => handleClick() }>Next Page</button>
</>
)
}
The suspense works when data is being fetched the first time, but I add searchParams, the data changes, but it never shows the suspense anymore. Any idea on how I can fix this?
This is the intended behavior, the Suspense/Await only do their work on the initial render. See When does the <Suspense /> fallback render? for details.
The
<Await />component will only throw the promise up the<Suspense>boundary on the initial render of the<Await />component with an unsettled promise. It will not re-render the fallback if props change. Effectively, this means that you will not get a fallback rendered when a user submits a form and loader data is revalidated. You will get a fallback rendered when the user navigates to the same route with different params.
The route will revalidate, e.g. call the loader function, under a few cases as described by shouldRevalidate. You should be specifically interested in the search params case.
There are several instances where data is revalidated, keeping your UI in sync with your data automatically:
- After an action is called from a .
- After an action is called from a <fetcher.Form>
- After an action is called from useSubmit
- After an action is called from a fetcher.submit
- When the URL params change for an already rendered route
- When the URL Search params change
- When navigating to the same URL as the current URL
You could use the useNavigation hook in Component and determine if the route is loading data again and conditionally render any loading UI.
Example:
import { Suspense } from "react";
import {
Await,
useLoaderData,
useNavigation, // <--
useSearchParams
} from "react-router-dom";
const Component = () => {
const { data } = useLoaderData();
const navigation = useNavigation(); // <--
const [searchParams, setSearchParams] = useSearchParams();
const handleClick = () => {
searchParams.set("page", (Number(searchParams.get("page")) ?? 0) + 1);
setSearchParams(searchParams);
};
return (
<>
<Suspense fallback={<>Loading Initial Data</>}>
<Await resolve={data}>
{(data) =>
navigation.state === "loading" ? ( // <--
<>Loading New Data</>
) : (
<>data: {data}</>
)
}
</Await>
</Suspense>
<button onClick={handleClick}>Next Page</button>
</>
);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With