swr
swr copied to clipboard
WIP: useSWRAggregator
This pr is trying to explore a possible solution for #1041 and #1988
Motivation
In most of time, if users want to render a list of useSWR hooks, they could do something like this.
const Item = ({ swrKey }) => {
const { data } = useSWR(swrKey, fetcher)
return <div>{data ? data : 'loading'}</div>
}
const Demo = () => {
const [keys] = useState(['/api/data?id=0', '/api/data?id=1', '/api/data?id=2'])
return <div>{keys.map(v => <Item key={v} swrKey={v} />)}</div>
}
But this pattern has some problems
- too much boilerplate code.
- user has to create key for their item component. comment
- user could not access aggregate result of swr hooks. comment
useSWRAggregator
Design
- using render props to reduce boilerplate code
- key for item component will be created by swr's build-in serialization
- user can access aggregate result from the result of useSWRAggregator and render props
Usage
- Simple
const Demo = () => {
const { data } = useSWRAggregator(keys, fetch)
return <>{data.map(v => <div key={v.key}>{v.data ? v.data : v.error.toString()}</div>)}</>
}
- Render props
const Demo = () => {
const { items } = useSWRAggregator(keys, fetch, {
keepPreviousData: true,
children: (swrResult, index, swrAggregator) => {
return <div>{swrResult.data ? swrResult.data : "loading"}</div>;
}
})
return <>{items}</>
}
- Toghter
const Demo = () => {
const { data, items } = useSWRAggregator(keys, fetch, {
keepPreviousData: true,
children: (value, index, array) => {
return <div>{value.data ? value.data : 'loading'}</div>
}
})
return (
<div>
<div>{items}</div>
<div>
{data ? (
data.map(v => (
<div key={v.key}>{v.data ? v.data : v.error.toString()}</div>
))
) : (
<div>loading</div>
)}
</div>
</div>
)
}
Problems
- Item component will use
useSWRinternally, it wouldn't share config withuseSWRAggregatorand needs extra code to configuseSWR
const Demo = () => {
const { items } = useSWRAggregator(keys, fetch, {
keepPreviousData: true,
children: (value, index, array) => {
return <div>{value.data ? value.data : 'loading'}</div>
}
})
// Has to use SWRConfig config useSWR in items
return <SWRConfig value={yourconfig}>{items}</SWRConfig>
}
config individually
const Demo = () => {
const { items } = useSWRAggregator(keys, fetch, {
keepPreviousData: true,
children: (value, index, array) => {
return <div>{value.data ? value.data : 'loading'}</div>
}
})
// Has to use SWRConfig config useSWR in items
return items.map(v => <SWRConfig value={yourconfig}>{items}</SWRConfig>)
}
Demo
https://codesandbox.io/s/useswraggregator-je1dxf
This pull request is automatically built and testable in CodeSandbox.
To see build info of the built libraries, click here or the icon next to each commit SHA.
Latest deployment of this branch, based on commit be97fb9d1e46011fe47614cabe7a48bc44f6f4a6:
| Sandbox | Source |
|---|---|
| SWR-Basic | Configuration |
| SWR-States | Configuration |
| SWR-Infinite | Configuration |
| SWR-SSR | Configuration |
| useSWRAggregator | PR |
any plan on crossing the finish line? look forward to using this feature
Would also like to utilize this! We have a workaround that involves looping thru the list of service calls, creating a component for each which uses the useSwr() hook, then utilizes a callback/reducer to send the data back to the parent which aggregates everything.
Our particular use case is we have data that's loading in different components throughout the page, but then also have a component that needs to know the status of which panels have had their data loaded already.