next.js: Updating search params does not trigger suspense fallback or loading.tsx
Verify canary release
- I verified that the issue exists in the latest Next.js canary release
Provide environment information
Operating System:
Platform: linux
Arch: x64
Version: #22 SMP Tue Jan 10 18:39:00 UTC 2023
Binaries:
Node: 18.14.2
npm: 9.5.0
Yarn: 1.22.19
pnpm: N/A
Relevant Packages:
next: 13.4.12
eslint-config-next: 13.4.12
react: 18.2.0
react-dom: 18.2.0
typescript: 5.0.4
Next.js Config:
output: N/A
Which area(s) of Next.js are affected? (leave empty if unsure)
App Router, Routing (next/router, next/navigation, next/link)
Link to the code that reproduces this issue or a replay of the bug
https://codesandbox.io/p/sandbox/muddy-glade-hn895s
To Reproduce
- Create a component which uses search parameters in fetching data
- Use a link to change the query param and load new data based on the search param
- Observe that loading.tsx fallback does not invoke and the page hangs while new data is loaded
Describe the Bug
Updating search params does not trigger suspense fallback or loading.tsx
Expected Behavior
Fetching new data based on new search params trigger suspense fallbacks or loading.tsx
Which browser are you using? (if relevant)
No response
How are you deploying your application? (if relevant)
No response
About this issue
- Original URL
- State: open
- Created a year ago
- Reactions: 41
- Comments: 26 (3 by maintainers)
Hello, i don’t know if this is an expected behavior or not, but i’ve stumbled on this behvior a little while ago and traced it back to React ( link : https://react.dev/reference/react/Suspense#resetting-suspense-boundaries-on-navigation ).
The thing is that for
Suspensefallbacks (andloading.tsxwhich is just anotherSuspense) to show, it needs to have a different key setup (<Suspense key={YOUR_KEY} />), it seems like next do not include the searchParams in the key of a route (forloading.tsx), so navigating to the same route do not retrigger the suspense fallback.My solution was just to include the searchParams into the key of the
Suspensefallback and it worked. Something like this :This won’t work for
loading.tsxfile though as that file do not take searchParams as props.Unfortunately, this solution wastes all the benefits of using server components.
Hi all, I tried a workaround and it works for me. Please try to convert your page.tsx to a client component using
"use client", get searchParams byuseSearchParams()instead of the page props and wrap the server component that fetch data in<Suspense>as follows.Hope it helps. Thanks.
page.tsxThanks for the response @Fredkiss3 ! I’m sure it will help someone.
Unfortunately for my scenario that won’t trigger the suspense boundary because I am loading new data via the a react server component. I would think the loading.tsx file would hit the fallback since that is the suspense boundary of my page.tsx.
@Fredkiss3
Thanks for the tweet thread, I hopped in the replies. Since NextJS is handling the boundaries, there should be a way to re-trigger the suspense boundary, whether that’s giving loading.tsx knowledge of the params, or having search params be included in the keys.
I’m not sure what @sebmarkbage means that search params are generally used differently.
If I’m not using them correctly in my bug, I can refactor to use params for my pagination. But having something like
app/page/[pageNumber]/page.tsxfeels overkill for paging through a table (especially when the result set can vary in length).edit:
I’ve updated the sandbox to include a refactored version of pagination using [pageNumber].
If anyone else runs into this issue (specifically with PPR), using regular html anchor tags worked for me. You don’t get all the benefits of the Next
<Link/>, but it shows the loading fallback until the team can implement client side navigation.I also heard back from Vercel. Even if it works locally, they say to take it up with Next since it’s an experimental feature. It’s not their problem, according to them (they were nice, I don’t mean to imply they weren’t).
I’ve encountered the same issue. If the API has a cold start when performing a search, I would like to show the “loading” state from loading.tsc file till the current request is finished.
Adding the key in Suspense worked for me, but then turned the entire route dynamic. I was hoping to use partial prerendering, but that only works if I remove they key from Suspense, which then causes the fallback to not trigger lol.
This works visually as expected, but causes the whole route to be dynamic
Edit: This only worked locally, and did not work when deployed.
@dclark27
The key thing seems to be how it is supposed to work : https://twitter.com/sebmarkbage/status/1688622875702345728?s=46
Normally if you want to trigger suspense boundaries, you have to fetch your data in a subcomponent not the page directly, this is fairly easy as you can pass props from the page to another component.
@ubirajaramneto Thanks for your suggestions. I appreciate you taking a look.
I have implemented them, but didn’t seem to change anything: https://ppr-loading-suspense-demo-git-ubira-e4da36-christopher-caldwell.vercel.app/ and https://github.com/christopher-caldwell/ppr-loading-suspense-demo/blob/ubirajara-suggestions/app/page.tsx
Something to note, your project does not have the
pprexperimental flag. I understand that I might be up a creek due to it being experimental, but wanted to point that out.For the wait, it is just to simulate the network taking longer than expected. It doesn’t wrap the call,
waitis a function that is awaited inside the API call function. I removed it anyway just to be sure.I put in a support ticket with Vercel, as this works when I run it on my computer with
yarn start. We shall see what happens.@ubirajaramneto Adding
unstable_noStoredid not change the result for me. It works local, but not hosted. Maybe my particular issue is with Vercel, and not Next itself.With Suspense key: https://ppr-loading-suspense-demo.vercel.app/?page=1 Without Suspense key: https://ppr-loading-suspense-demo.vercel.app/without-suspense-key?page=1
I mostly want to know if this behavior is considered intentional for where the dev team is in the development process of PPR. I understand that features will trickle in, but is this supposed to be happening? At least for now.
Edit:
yarn buildand thenyarn starton my local machine, and this works as expected. I think my issue might be with Vercel in their hosting.For people that are still not able to get this to work correctly, here is what worked for me.
Some context before we move on. The react documentation states the following:
So with that in mind, make sure that the following is true:
1 - The actual data loading is happening in the child, and not the same component where the Suspense component lives. 2 - Make sure that you assign the key to the Suspense component, and not the child component itself.
NOTES:
Although I am unsure of the consequences of adding a key to a Suspense component, this seemed to work well and solved the issue I was having. Maybe this is an anti pattern for Suspense specifically? Time will tell.
Both of the components shown below are server components. I am unsure if applying the same strategy would work if the child component was a client component, but from the react documentation it states the following:
So it should work for client components, if the conditions above are met.
Here is an example:
I somewhat agree with you. However, given that my app is kind of light-weighted and it’s acceptable for me to shift the rendering to client side.
Got the same problem. I tried @Fredkiss3 's solution by passing a key to <Suspense> but it didn’t work, not even in dev stage.
I’ve got the same issue Suspense isn’t being triggered for searchParams at all.
@dclark27 did you find a solution for this problem ?