React

January 07, 2019

monorepo

https://itnext.io/guide-react-app-monorepo-with-lerna-d932afb2e875

create react app

create-react-app my-app --typescript

with lerna

lerna add @types/jest
lerna add @types/node
lerna add @types/react
lerna add @types/react-dom
lerna add react
lerna add react-dom
lerna add react-scripts
lerna add typescript
lerna add tslint

Performance

Context

The way that context works is that whenever the provided value changes from one render to another, it triggers a re-render of all the consuming components (which will re-render whether or not they're memoized).

When:

  • Your context value changes frequently
  • Your context has many consumers
  • You are bothering to use React.memo (because things are legit slow)
  • You've actually measured things and you know it's slow and needs to be optimized

Tips:

  • Slice context up when possible
  • Use memo within context if needed

Large App State

State Decision Tree

  • Use HOC to handle memoization

  • Recoil

Performance Monitoring

Async (Suspense)

  • React renders components in try/catch, if you throw a promise during render if it's not ready it will update when ready
const pokemonPromise = fetchPokemon("pikachu").then(
  (pokemonData) => (pokemon = pokemonData),
);

function PokemonInfo() {
  if (!pokemon) {
    throw pokemonPromise;
  }

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

Error Handling

if (pokemonError) {
  throw pokemonError;
}

<ErrorBoundary>
  <React.Suspense fallback={<div>loading...</div>}>Yo</React.Suspense>
</ErrorBoundary>;

Promises inside render

  • Dangerous, don't assume render called only once
  • Use a cache to resolve
const promiseCache = {};
function MySuspendingComponent({ value }) {
  let resource = promiseCache[value];
  if (!resource) {
    resource = doAsyncThing(value);
    promiseCache[value] = resource; // <-- this is very important
  }
  return <div>{resource.read()}</div>;
}

✅ ⚠️ ⛔

Fetch on Render (default)

✅ benefits from colocation ✅ fetch when component renders ⛔ User may see empty content ⛔ Takes time

Fetch than render

⛔ empty content

Render as fetch

✅ Fetch data and assets as soon as you have the assets you need (preload) ⚠️ Lose the benefits of colocation unless split into two files (data and component)

Suspense List