Conversation
|
This pull request is being automatically deployed with Vercel (learn more). 🔍 Inspect: https://vercel.com/pmndrs/jotai/Csjk43uQFDFttPeiuaPAk7fpSESe |
|
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 348ad75:
|
|
@Pinpickle Would you be able to try this if it doesn't break your use case? |
|
Size Change: +621 B (+2%) Total Size: 41.4 kB
ℹ️ View Unchanged
|
|
This looks good to me @dai-shi - if the tests pass then it works for my usecase! I would suggest adding these tests (which are passing), just to make sure it's not getting tripped up by any async logic in the mix: it('loadable immediately resolves sync values', async () => {
const syncAtom = atom(5)
const effectCallback = jest.fn()
const { getByText } = render(
<Provider>
<LoadableComponent effectCallback={effectCallback} asyncAtom={syncAtom} />
</Provider>
)
getByText('Data: 5')
expect(effectCallback.mock.calls).not.toContain(
expect.objectContaining({ state: 'loading' })
)
expect(effectCallback).toHaveBeenLastCalledWith({ state: 'hasData', data: 5 })
})
it('loadable can use resolved promises syncronously', async () => {
const asyncAtom = atom(Promise.resolve(5))
const effectCallback = jest.fn()
const ResolveAtomComponent = () => {
useAtomValue(syncAtom)
return <div>Ready</div>
}
const { getByText, findByText, rerender } = render(
<Provider>
<Suspense fallback={null}>
<ResolveAtomComponent />
</Suspense>
</Provider>
)
await findByText('Ready')
rerender(
<Provider>
<LoadableComponent effectCallback={effectCallback} asyncAtom={asyncAtom} />
</Provider>
)
getByText('Data: 5')
expect(effectCallback.mock.calls).not.toContain(
expect.objectContaining({ state: 'loading' })
)
expect(effectCallback).toHaveBeenLastCalledWith({ state: 'hasData', data: 5 })
})It does require a slight change to the interface LoadableComponentProps {
asyncAtom: Atom<Promise<number> | Promise<string> | string | number>
effectCallback?: (loadableValue: any) => void
}
const LoadableComponent = ({
asyncAtom,
effectCallback,
}: LoadableComponentProps) => {
const value = useAtomValue(loadable(asyncAtom))
useEffect(() => {
if (effectCallback) {
effectCallback(value)
}
}, [value, effectCallback])
if (value.state === 'loading') {
return <>Loading...</>
}
if (value.state === 'hasError') {
return <>{String(value.error)}</>
}
// this is to ensure correct typing
const data: number | string = value.data
return <>Data: {data}</>
} |
|
Added the tests. Thanks! |
This is full refactor of the loadable util, introduced in #734. The previous implementation doesn't work with #854.