Reace Hooks その③

Next.js-2.React Hooks編-

useStateで配列を更新しリアルタイムで表示を変える

今回はuseStateで配列の値を管理し、それをリアルタイムで表示していきます。

今回の書き方は管理者側の更新画面などでReactで頻繁に出てくるものなので、少し複雑ですが頑張っていきましょう。

app/componentsフォルダに「todoList.js」を作成しTodoListコンポーネントを定義します。

"use client";

import { useState } from "react";

export default function TodoList() {
    // 配列を `useState` で管理
    const [items, setItems] = useState([]);
    const [text, setText] = useState("");

    // 入力値を更新
    const handleChange = (e) => {
        setText(e.target.value);
    };

    // 配列に新しいアイテムを追加
    const addItem = () => {
        setItems([...items, text]); // 新しい配列を作成(スプレッド構文)
        setText(""); // 入力欄をクリア
    };

    return (
        <div>
            <h2>Todo List</h2>
            <input type="text" value={text} onChange={handleChange} />
            <button onClick={addItem}>追加</button>

            <ul>
                {items.map((item, index) => (
                    <li key={index}>{item}</li>
                ))}
            </ul>
        </div>
    );
}

次にapp/page.jsでTodoListコンポーネントを読み込みます。

import TodoList from "./components/todoList";
<TodoList />

このように、inputタグに入力し、「追加」ボタンをクリックするとリストがリアルタイムで増えていきます。

コード解説

上からTodoListコンポーネント内のコードを順に解説していきます。

useStateを使って、リスト用の配列「items」と入力値の管理用の値「text」を定義しています。

初期値はそれぞれ空の配列と空の文字列です。

const [items, setItems] = useState([]);
const [text, setText] = useState("");

次に、textを更新するイベントハンドラ「handleChange」関数を定義しています。

 const handleChange = (e) => {
        setText(e.target.value);
    };

そしてitemsを更新するイベントハンドラ「addItem」関数を定義しています。

const addItem = () => {
        setItems([...items, text]); // 新しい配列を作成(スプレッド構文)
        setText(""); // 入力欄をクリア
    };

ここで見慣れない書き方がされています。

setItems([...items, text]);

これは、元のitemsをスプレッド構文で展開しそれにtextの値を足した新しい配列を新しいitems配列として定義・更新しています。

stateで扱う値は直接変更できない。というルールがあるため、元の配列に要素を追加するのではなく、新たな配列として定義する形をとっています。

また、下記のように値を使用したら空にしてクリアするのもReactでは一般的な作法となります。

 setText("");

JSXでは「追加」ボタンをクリックしたらinputタグに入力されている値が<li>タグとして追加される記述をしています。

 return (
        <div>
            <h2>Todo List</h2>
            <input type="text" value={text} onChange={handleChange} />
            <button onClick={addItem}>追加</button>

            <ul>
                {items.map((item, index) => (
                    <li key={index}>{item}</li>
                ))}
            </ul>
        </div>
    );

まず見慣れないのは<ul>の中身です。

  {items.map((item, index) => (
     <li key={index}>{item}</li>
  ))}

mapメソッドを使ったリスト作成

mapメソッドは元の配列の各要素を加工して新しい配列を作るJavascriptのメソッドです。

今回の記述だと、items配列の各要素を基に<li>JSXタグを要素とする配列を作っています。

最後に、indexとkeyについて説明します。

<li key={index}>{item}</li>

ここで「key」をmapメソッドの生成するindexの値を入れていますが、

Reactではリストには「key属性」を必ず指定するというルールがあるためです。

なぜこのようなルールがあるかについての詳細な説明は省きますが、ルールとして覚えておいてください。

また、今回のindexの指定の仕方だと、実はリストの「変更」「削除」があるような場合には不適切です。

こちらもまた今後解説します。

textのstateを作った理由(※飛ばしてもOK)

こちらは興味のある方のみでOKですが、今回stateで管理する値を

  • test
  • items

の2つ用意しました。

JQueryでのDOM操作に慣れている方なら、

「addItem」関数内で直接inputタグの値を参照すればよいのでは?と思うかもしれません
例:)

const addItem = () => {
    const inputValue = document.querySelector("input").value; 
    setItems([...items, inputValue]);
};

これは実は動くことは動くのですが、以下の理由で推奨されません。

  1. 更新タイミングがずれる可能性がある(値が最新でない)。
  2. 入力欄のクリアが難しい。
  3. 直接 DOM を操作している(React の流儀に反する)。

stateが更新される度に画面が更新(再レンダリング)されるため、stateを使わないと値が最新でない可能性があるというのが一番の理由になります。

このstateが更新される度に画面が更新(再レンダリング)されるという特性は重要なReactの機能なので覚えておいてください。

コメント

タイトルとURLをコピーしました