Using Suspense within our component isn't exactly ergonomic. Let's put all that logic into a reusable function so we can create resources anytime we need them and for any asynchronous interaction in our app.

 

In previous post, we have see how to use React.Suspense to handle data fetching, with fallback and ErrorBoundary. 

In this post, we will refactor code to make a generic function to handle all use cases.

function createFetch(fetchFn) {
  let status = 'pending'
  let result
  let error
  let promise = fetchFn().then(
    p => {
      console.log('promise resolve')
      status = 'success'
      result = p
    },
    e => {
      status = 'error'
      error = e
    },
  )

  return {
    read() {
      if (status === 'error') {
        throw error
      }

      if (status === 'pending') {
        throw promise // this API might change
      }

      if (status === 'success') {
        return result
      }
    },
  }
}

 

Use:

const promise = createFetch(() => fetchPokemon('pikachu'))

function PokemonInfo() {
  console.log('PokemonInfo init')

  const pokemon = promise.read()

  return (
    <div>
      <div className="pokemon-info__img-wrapper">
        <img src={pokemon.image} alt={pokemon.name} />
      </div>
      <PokemonDataView pokemon={pokemon} />
    </div>
  )
}