Please take a look at the sandbox: https://codesandbox.io/s/hardcore-thunder-vgbvt?file=/src/Screen.tsx
Purpose:
Explanation:
Questions:
I think I'd keep all the data in an atom, and then have the loading of new data not be Recoil but instead an async function, and then set the new state when the data is fetched. That way you always have some state in your atom, and the page won't flash white when loading.
I think I'd keep all the data in an atom, and then have the loading of new data not be Recoil but instead an async function, and then set the new state when the data is fetched. That way you always have some state in your atom, and the page won't flash white when loading.
Yes, I know. It's the traditional way. I'm trying to implement things in the Recoil way and Suspense.
I have adjusted a bit. I made the local "last" state as an atom and register it as a dependency in the "Chunk". Chunk becomes a selector instead of selectorFamily. "list" stay local state, it can be an atom of course. But I prefer keeping it local.
In that case, I'd probably have two atoms, one for the actual state, and one for the previous state. You can register an atom effect in the main atom, that sets the old value in the other atom each time it's chabged.
Then in the React component using the data, you can use useRecoilValueLoadable to get a loadable for the main atom. Then if the loadable state is 'loading' you can use the old data, and then when the new arrives use that instead. You could even extract that part into a hook.
Sorry for formatting/spelling mistakes, typing this on mobile.
See also https://github.com/facebookexperimental/Recoil/issues/290 for a previous discussion on the subject.
Depending on the behaviour you want, there are different approaches to take. If you want Suspense to be pending while incrementally loading then you can use a selector as your example to represent the loading. You may want to use a selector to actually combine the chunks as it seems like the example effect only appends regardless of the index, though it's probably just a simple example. If you don't want Suspense to suspend the <DataList> component, then, as @BenjaBobs suggests, you could use an atom to represent the current list state and asynchronously adjust it as chunks are loaded. If you want to show some indication that the appending to the list is pending, then you could add some additional spinner based on the async state of the additional fetch. Another alternative @BenjaBobs refers to in #290 would be to use a selector to merge the chunks, but then implement an abstraction or experiment with the new useTransition() React Concurrent Mode hook to render the previous state while the new state is pending.
In that case, I'd probably have two atoms, one for the actual state, and one for the previous state. You can register an atom effect in the main atom, that sets the old value in the other atom each time it's chabged.
Then in the React component using the data, you can use
useRecoilValueLoadableto get a loadable for the main atom. Then if the loadable state is'loading'you can use the old data, and then when the new arrives use that instead. You could even extract that part into a hook.Sorry for formatting/spelling mistakes, typing this on mobile.
Nice solution. Thank you!
Depending on the behaviour you want, there are different approaches to take. If you want Suspense to be pending while incrementally loading then you can use a selector as your example to represent the loading. You may want to use a selector to actually combine the chunks as it seems like the example effect only appends regardless of the index, though it's probably just a simple example. If you don't want Suspense to suspend the
<DataList>component, then, as @BenjaBobs suggests, you could use an atom to represent the current list state and asynchronously adjust it as chunks are loaded. If you want to show some indication that the appending to the list is pending, then you could add some additional spinner based on the async state of the additional fetch. Another alternative @BenjaBobs refers to in #290 would be to use a selector to merge the chunks, but then implement an abstraction or experiment with the newuseTransition()React Concurrent Mode hook to render the previous state while the new state is pending.
Actually, I'm trying to implement an endless scroll. I want to get more data and append to the list when it reaches the end, seamlessly, without flashing or loading. @BenjaBobs suggestion is nice. I'm looking into #290. But I think React Concurrent Mode is interesting too.
Instead of an atom synced for previous state, also consider a usePrevious() type of hook (there are a few implementations out there) for rendering based on previous state.
Most helpful comment
See also https://github.com/facebookexperimental/Recoil/issues/290 for a previous discussion on the subject.