React Coroutine

Async components made easy. No API, just language features.

Next list of small code examples attempts to show the advantages of React Coroutine in solving different tasks.

Code Splitting

An example of coroutines usage for async data fetching and dynamic imports.

import React from 'react';
import Coroutine from 'react-coroutine';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Pokemons from './PokemonAPI';

export default (
  <Router>
    <article>
      <h1>Pokemons</h1>
      <Route exact path="/" component={Coroutine.create(PokemonListLoader)} />
      <Route exact path="/:pokemonId" component={Coroutine.create(PokemonInfoLoader)} />
    </article>
  </Router>
);

async function PokemonListLoader() {
  let { default: PokemonList } = await import('./PokemonList');
  return <PokemonList />;
}

async function* PokemonInfoLoader({ match }) {
  let module = import('./PokemonInfo');
  let pokemonInfo = Pokemons.retrieve(match.params.pokemonId);
  yield <p>Loading...</p>;
  let [{ default: PokemonInfo }, data] = await Promise.all([module, pokemonInfo]);
  return <PokemonInfo data={data} />;
}

Search Form

An example of progressive rendering with loading spinner and requests debouncing.

import React from 'react';
import Coroutine from 'react-coroutine';
import SearchAPI from './SearchAPI';
import SearchResults from './SearchResults';
import ErrorMessage from './ErrorMessage';

export default Coroutine.create(SearchForm);

async function* SearchForm({ query }) {
  if (query.length === 0) return null;

  yield <p>Searching {query}...</p>;

  try {
    let { results } = await SearchAPI.retrieve(query);
    return <SearchResults results={results} />;
  } catch (error) {
    return <ErrorMessage error={error} />;
  }
}