Sikau

Project: The café front end · Day 3 · about 40 min

Loading data with effects

A custom hook with loading, error and ready states — and no race conditions.

Loading, error, ready

Data arrives later — or not at all. A good screen shows *loading*, then the data or a clear error. And when the learner switches dishes fast, an old slow answer must never overwrite a newer one: that's what the effect's cleanup is for.

useDish

function useDish(slug) {
  const [state, setState] = useState({ status: "loading" });
  useEffect(() => {
    let ignore = false;
    setState({ status: "loading" });
    fetchDish(slug).then(
      (dish) => { if (!ignore) setState({ status: "ready", dish }); },
      (error) => { if (!ignore) setState({ status: "error", error: error.message }); },
    );
    return () => {
      ignore = true;
    };
  }, [slug]);
  return state;
}

export default function App() {
  const [slug, setSlug] = useState("momo");
  const result = useDish(slug);
  return (
    <>
      <select id="pick" value={slug} onChange={(e) => setSlug(e.target.value)}>
        <option value="momo">Momo</option>
        <option value="thukpa">Thukpa</option>
        <option value="pizza">Pizza</option>
      </select>
      {result.status === "loading" && <p id="status">Loading…</p>}
      {result.status === "error" && <p id="error" role="alert">{result.error}</p>}
      {result.status === "ready" && (
        <article>
          <h2 id="name">{result.dish.name}</h2>
          <p id="price">Rs {result.dish.price}</p>
        </article>
      )}
    </>
  );
}

The rest of this lesson

  • Modelling the statesexplain
  • Why the ignore flag mattersexplain
  • Without cleanuppredict
  • Switching dishes fastorder
  • Write useDishwrite code
  • Badge quizquiz
  • What you builtrecap

Continue this lesson free — run real code in your browser

Continue with Google

See all 5 lessons of Project: The café front end