React · LEARN AT YOUR OWN PACE今日も、一歩ずつ。

LESSON 07 · 約30分

状態を持ち上げ、二つの部品をつなぐ

同じ情報を使う部品の共通の親にstateを置き、計算できる値を減らします。

コードを試す前に

01のVite reactテンプレート(JavaScript/JSX)を使います。特記のないApp.jsxは、そのレッスンだけで動く独立した例です。例同士を連結しないでください。

短い学習用の例です。各App.jsxは独立した例で、順に追記して一つの完成品にする形式ではありません。ファイル名、依存関係、未定義部分の前提は注記に記載します。問題内の抜粋や空欄は、そのまま実行するための完成コードではありません。

開発環境の準備を確認する →

このレッスンでわかること

  • 共通の親へstateを移動できる
  • 入力stateと計算結果を区別できる

値は一か所を正とする

検索欄と結果一覧が同じキーワードを使うなら、両者の共通の親がqueryを持ちます。子へ値と変更通知の関数を渡し、親で更新します。子ごとに同じ値のstateを置いてEffectで合わせると、ずれや余分な処理が増えます。

計算で出る値はstateにしない

検索結果はitemsとqueryからfilterで計算できます。件数も結果のlengthで分かります。元データ・検索語・検索結果・件数を全部stateにすると、ひとつ更新し忘れたときに表示が矛盾します。最小の状態と、その状態から導く表示に分けましょう。

データは下へ、操作の通知は上へ

子はonQueryChangeのようなpropsを呼び、親に変更を知らせます。子が親の変数を直接書き換えるわけではありません。まずpropsで関係を明示し、受け渡しが深く複雑になってからContextを検討します。

検索欄と一覧を分離する

src/App.jsx
import { useState } from 'react';

const topics = [
  { id: 1, title: 'JSX' },
  { id: 2, title: 'props' },
  { id: 3, title: 'state' },
];

function SearchBox({ query, onQueryChange }) {
  return <label>検索語
    <input value={query} onChange={event => onQueryChange(event.target.value)} />
  </label>;
}

function Results({ items }) {
  return items.length === 0 ? <p>一致するテーマがありません。</p> : (
    <ul>{items.map(item => <li key={item.id}>{item.title}</li>)}</ul>
  );
}

export default function App() {
  const [query, setQuery] = useState('');
  const normalized = query.trim().toLowerCase();
  const visible = topics.filter(topic => topic.title.toLowerCase().includes(normalized));

  return (
    <main>
      <h1>テーマを探す</h1>
      <SearchBox query={query} onQueryChange={setQuery} />
      <p role="status">{visible.length}件</p>
      <Results items={visible} />
    </main>
  );
}

visibleは描画中の計算結果です。検索のたびに通信しない、固定データの小さな例です。

TRY IT YOURSELF

検索欄と一覧をつなぐ

  1. 大文字・小文字や前後の空白があっても同じ検索結果になるか確かめる
  2. 一致しない語を入れて0件表示を確認する
  3. queryを空文字へ戻すクリアボタンを親へ追加する
  4. stateを持つのが親だけであることをコード上で確認する

できたらOK:入力・件数・結果が常に一致し、Effectで検索結果をコピーしていない

QUICK CHECK

理解を確かめよう

検索欄と結果一覧で同じ検索語を使いたい。最初の設計として適切なのはどれ?

公式資料でもう少し詳しく

ここまで読めたら、ひとつ前進。