- What and why is it?
- "boundary"
- "fallback"
- "transition"
Suspense
andSuspenseList
- How it impacts components
createRoot
createBlockingRoot
Suspense
fallback
SuspenseList
revealOrder
:forwards|backwards|together
useTransition
useDeferredValue
- Use dynamic
import()
to import thePokemonDetail
module - Wrap it in
React.lazy
soReact.Suspense
knows what to do with it - The app breaks because it loads with the component it needs to render. this means it's working
- Use an error boundary component to catch errors and provide a fallback
- Now, read and fix the error!
- Add a
React.Suspense
component around async component - Provide a fallback prop with any renderable
fallback={<div>...fetching pokemon</div>}
- As an experiment, wrap the
initialPokemon
object in aPromise.resolve
- Like
React.lazy
, promises need a wrapper to communicate withSuspense
boundaries. Import the smallsuspensify
utility into the app.import { suspensify } from "./api";
- Wrap our
initialPokemon
resolved promise insuspensify
- Call the
read()
function in the consuming component (PokemonDetail
)
Play with all the options...
-
promise.resolve({ ... })
-
Promise.reject()
-
new Promise(() => {})
-
fetchPokemon(1)
-
Finally, use
fetchPokemon
(also provided as a named export fromapi.js
)
let [pokemon] = React.useState(initialPokemon)
- Note that we're putting the whole pokemon here, not just the number
- Note also that the
useState
hook is totally fine holding an unresolved promise
- Take the updater function from
useState
let [pokemon, updatePokemon] = React.useState(initialPokemon);
- ...
updatePokemon(suspensify(updatePokemon(2)))
- Try
suspensify(updatePokemon(pokemon.id + 1))
- It doesn't work because
pokemon
isn't a resolved value in this scope - we can only use it where the component calls
.read()
. remember .read()? - this will impact how you write code.
- let's update the component and then teach it some composability
-
- (we have a short ammount of time so i'll show you how i solved it)
-
- (move the button in first.)
- startTransition w/timeout to set how long until flash off fallback
- unstable_createRoot to turn it on
- isPending to show some loading state
- isPending to show change color to gray (1. useDeferredValue but short on time)
- use oversimplified PokemonList componenent that does all of it's own data-fetching
- we're slowing this call down to 2 seconds
- if we put it in the same error boundary, they load together
- we can do better. we'd like to load the first available
- use different suspense boundaries
- we can still do layout
revealOrder: "forwards" | "backwards" | "together"
tail: "collapsed" | "hidden"