Kent C. Dodds: Let's learn the fundamentals of React Suspense. The code that I'm about to write is definitely not a code that you're going to write in your typical code base, but it's how the abstractions that you're going to be using with Suspense work under the hood.
Here we have a simple Pokémon app that will fetch us data about a particular Pokémon. If we put Mew in here, then it should fetch us data about that Pokémon that we can render here with some JSON.
To fetch this data, we have this fetchPokemon API that we can call. That's a graphql API. All we need to do is pass it a name, and it will get us that Pokémon's ID, number, name, and attacks.
The first thing that we're going to do is we need to bring in Suspense, so we have something that can handle the asynchrony. Then here, I'm going to render this PokemonInfo inside of Suspense. In the Suspense, we'll say, "Fallback is a div that says, 'Loading.'" Next, let's go ahead and create a cache. That's just going to be an object that will keep track of all of the Pokémon that we've loaded.
Then I'm going to get the Pokémon from the cache by the PokemonName. If there's not a Pokémon, then we're in trouble. Let's do something. Otherwise, we have our Pokémon and we can render it out.
Here if I say Mew stuff is hi, and then we go here and say Mew, then we're going get stuff is hi. If we go and say Pikachu, for example, then we're going to get unknown.
How do we call this fetchPokemon so that we can load up our cache with real actual data, rather than having to hardcode some fake data in here? What we're going to do is write in our render method.
We'll say Const promise = fetchPokemon. We'll pass the PokemonName. Then, when that has resolved, we'll take that Pokémon that it resolves to. We'll say, Cache@PokemonName = that Pokémon that we've resolved to.
Then here's the real trick. We're going to throw that promise. When we throw this promise, React will catch that promise and find the closest Suspense component and use its fallback to render that instead until the Pokémon has been loaded.
When this promise resolves, then Suspense is going to re-render its children. At that point in time, because our promise set that Pokémon data in the cache by the PokemonName, the next time this renders, it's going to check the cache by that PokemonName, and it will have that Pokémon's data.
Let's go and save this. We'll give this a try. We'll say Mew and submit that. We get all of the data. If we say Pikachu, then we'll get Pikachu's data. Now, if we say Mew again, that data is already in the cache, so it loads instantly.
If we say Mew2, then it's going to take some time before it actually loads the data, and we'll see that loading state. This is definitely not something that you would want to actually do in production. There are a couple of problems here.
For example, if this Pokémon info were to be re-rendered two times in a row before this fetchPokemon resolves, then we're going to fire off two promises. That's not optimal. There are a whole bunch of other concerns around cache and validation that are also suboptimal.
In addition, this is definitely not a code that I would want to write in my function components, but hopefully this gives you a good idea of what's going on under the hood when we start using other abstractions like React Cache.