cf.completefrontend

Write the codeHard

Write a list with useOptimistic that adds items at once and rolls back when saving fails

Write TeaList, the default export. It takes initialTeas, an array of { id, name }, and saveTea(name), which returns a promise of the saved tea, { id, name }, or rejects when saving fails.

Show the teas in a list, one list item each, and below it a form with a text box labelled Tea (its name is name) and an Add button. Submit the form with a form action. Trim the name, and add nothing when it's empty.

A new tea shows at the end of the list at once, as Sencha (saving…) (with the single … character), while saveTea runs. When it resolves, the saved tea takes its place. When it rejects, the tea disappears and an element with role="alert" says Couldn't add Sencha.; the next tea that saves clears that message. Several teas can be saving at once, and each one must show.

<TeaList initialTeas={[{ id: 1, name: "Assam" }]} saveTea={saveTea} />
 
// Assam
// Sencha (saving…)
// [Tea: ______] [Add]
Write this (App.jsx)
import { startTransition, useOptimistic, useState } from "react";
 
export default function TeaList({ initialTeas = [], saveTea }) {
  const [teas, setTeas] = useState(initialTeas);
 
  async function addTea(formData) {
    const name = String(formData.get("name") ?? "").trim();
    if (!name) return;
    // TODO: show the tea at once, marked (saving…), and roll it back if saveTea fails.
    const saved = await saveTea(name);
    startTransition(() => setTeas((current) => [...current, saved]));
  }
 
  return (
    <>
      <ul>
        {teas.map((tea) => (
          <li key={tea.id}>{tea.name}</li>
        ))}
      </ul>
      <form action={addTea}>
        <label>
          Tea <input name="name" />
        </label>
        <button>Add</button>
      </form>
    </>
  );
}
The checks your code must pass
  • shows the teas it starts with
  • shows a new tea at once, marked (saving…)
  • swaps in the saved tea when saveTea answers
  • rolls back and explains when saveTea fails
  • shows every tea that is saving at once
  • a saved tea never shows next to its pending copy
  • adds nothing for an empty name
  • a tea that saves clears the old message

Try it in the editor

The answer

Write it yourself first. Then compare it with a reference solution and the checks it passes.

Checking your sign-in…