← Back to the exercise

Adding a show

The answer to the exercise in Adding a show.

watchlist.push(...) mutates the array React already holds, so the saved list never updates. Spread a new array, and copy the show with { ...show, watched: false }.

import { useState } from "react";
import "./styles.css";
import { fromTvmaze } from "./show";
import SearchForm from "./SearchForm";
import ShowList from "./ShowList";

const start = [
  { id: "s1", title: "The Bear", year: 2022, genre: "Drama", genres: ["Drama"], rating: 8.6, still: "still-warm", watched: false },
  { id: "s2", title: "Severance", year: 2022, genre: "Thriller", genres: ["Thriller"], rating: 8.7, still: "still-cold", watched: false },
  { id: "s3", title: "Andor", year: 2022, genre: "Sci-Fi", genres: ["Sci-Fi"], rating: 8.4, still: "still-dusty", watched: true },
];

export default function App() {
  const [watchlist, setWatchlist] = useState(start);
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([
    { id: "99", title: "Slow Horses", year: 2022, genre: "Thriller", genres: ["Thriller"], rating: 8.4, still: "still-warm", watched: false, image: null },
  ]);
  const [status, setStatus] = useState("idle");

  function handleToggle(id) {
    setWatchlist(
      watchlist.map((show) =>
        show.id === id ? { ...show, watched: !show.watched } : show
      )
    );
  }

  function handleAdd(show) {
    setWatchlist([...watchlist, { ...show, watched: false }]); // new array
  }

  async function handleSearch(event) {
    event.preventDefault();
    const trimmed = query.trim();
    if (!trimmed) {
      setResults([]);
      setStatus("empty");
      return;
    }

    setStatus("loading");
    setResults([]);

    try {
      const response = await fetch(
        "https://api.tvmaze.com/search/shows?q=" +
          encodeURIComponent(trimmed)
      );
      if (!response.ok) {
        throw new Error("Request failed");
      }
      const data = await response.json();
      setResults(data.map((item) => fromTvmaze(item.show)));
      setStatus("success");
    } catch {
      setStatus("error");
    }
  }

  const watched = watchlist.filter((show) => show.watched).length;

  return (
    <div className="page">
      <header className="header">
        <h1>My watchlist</h1>
        <p className="count">
          {watchlist.length} shows · {watched} watched
        </p>
      </header>
      <SearchForm
        query={query}
        onQueryChange={setQuery}
        onSearch={handleSearch}
        disabled={status === "loading"}
      />
      {status === "loading" ? (
        <p className="status">Searching…</p>
      ) : null}
      {status === "empty" ? (
        <p className="status">Type a show name first.</p>
      ) : null}
      {status === "error" ? (
        <p className="status status-error">
          Could not load shows. Try again.
        </p>
      ) : null}
      {status === "success" && results.length === 0 ? (
        <p className="status">No shows for that name.</p>
      ) : null}
      {results.length > 0 ? (
        <div className="results">
          <p className="section-title">Results</p>
          <ShowList shows={results} onAdd={handleAdd} />
        </div>
      ) : null}
      <ShowList shows={watchlist} onToggle={handleToggle} />
    </div>
  );
}