Replies: 6 comments
-
I was wondering about this as well. |
Beta Was this translation helpful? Give feedback.
-
You could use const data = await fetcher("/api/resource/1");
mutate("/api/resource/1", data, false); // the false is to avoid a revalidation in SWR You could do this multiple times before rendering your component, now when a component using SWR with suspense enabled is rendered it will read from the pre-filled cache, if it's already there the component will render immediately without showing the Suspense fallback. |
Beta Was this translation helpful? Give feedback.
-
Hi all! Happy to hear about your feedback on #168 🙏 |
Beta Was this translation helpful? Give feedback.
-
I'm working on my own project to simply avoid the waterfalls in this way. If it helps. // Component.tsx
import { useSWR } from './WrappedSwr'
export const Component = () => {
const resource1 = useSWR<YourResponseType1>('/path1', fetcher) // fetch1
const resource2 = useSWR<YourResponseType2>('/path2', fetcher) // fetch2
const data1 = resource1.read() // throw proimse
const data2 = resource2.read() // throw proimse
// or you can pass the resource to a child component
// return (
// <Suspense>
// <Child resource={resource1} /> // props.resource.read() in Child Component
// </Suspense>
// )
// ... // WrappedSwr.ts
import useRawSWR, { mutate, responseInterface } from 'swr'
const useSWR = <Data>(
key: string,
fetcher: (args: any) => Data | Promise<Data>,
): Resource<Data> => {
try {
const res = useRawSWR<Data>(key, fetcher)
// If the data is in swr's cache
return { read: () => res.data as Data }
} catch (promiseOrError) {
if (typeof promiseOrError.then === 'function') {
return wrapPromise<responseInterface<Data, Error>>(promiseOrError)
}
throw promiseOrError
}
}
// from: https://codesandbox.io/s/frosty-hermann-bztrp?file=/src/fakeApi.js
function wrapPromise<T extends { data?: any }>(promise: Promise<T>) {
let status: 'success' | 'pending' | 'error' = 'pending'
let result: T | Error
const suspender = promise.then(
(r) => {
status = 'success'
result = r
},
(e) => {
status = 'error'
result = e
},
)
return {
read() {
if (status === 'pending') {
throw suspender
} else if (status === 'error') {
throw result
} else if (status === 'success') {
return (result as T).data
}
throw new Error('unknown status in wrapPromise')
},
}
}
export { useSWR, mutate } |
Beta Was this translation helpful? Give feedback.
-
Here's my solve: https://medium.com/@tamis.mike/useswr-parallel-suspense-b41929a01098 |
Beta Was this translation helpful? Give feedback.
-
I agree with the idea of avoiding waterfalls by separating the declaration of asynchronous request calls from their data consumption, similar to approaches using a read() method or proxies. Now that https://react.dev/reference/react/use is available, it's not necessary for useSWR to resolve the Promise internally; users can resolve the Promise using use as needed. How about providing an option in useSWR to return the Promise directly without resolving it? function MyComponent() {
// useSwr is called, initiating the fetch, but returns the Promise
// Note: The actual API might differ. '{ returnPromise: true }' is illustrative.
const userPromise = useSwr('/api/user', fetcher, { returnPromise: true });
const productsPromise = useSwr('/api/products', fetcher, { returnPromise: true });
// Use React.use to resolve the Promises within the component body
// This will trigger Suspense if the Promises are not yet resolved
const user = React.use(userPromise);
const products = React.use(productsPromise);
// Now user and products contain the resolved data
return (
<div>
<h1>Welcome, {user.name}</h1>
<p>You have {products.length} products.</p>
</div>
);
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Side note: I am writing this with my jaw on the floor. What a clean API. Nice work guys. 😍
This issue refers to the idea of waterfalls as mentioned in the react docs.
https://reactjs.org/docs/concurrent-mode-suspense.html#for-library-authors
From a glance, it appears that the suspense based API does not take the above optimization into consideration. If I am not mistaken, to avoid waterfalls, we need to declare the API calls first(which will init the fetch calls), and then read the data from another call (
read
method in relay), which will throw the promise.Is this already done in the library? If not, do you guys plan to do it in the future? How would the API look like?
PS: In my head, the API should look something like below
Beta Was this translation helpful? Give feedback.
All reactions