【React x TypeScript】useStateで配列に要素の追加、または要素の一部を更新する方法

タイトルの通りのことをやりますが、けっこうハマったので備忘録として残しておきます。

useStateで配列に要素の追加、または要素の一部を更新する方法

今回使用した環境

インターネット接続可能のオンラインの環境

64 ビット オペレーティング システム

Windows 10 22H2
react-dom@18.2.0
react-scripts@5.0.1
react@18.2.0
typescript@4.9.4

2パターンの配列をuseStateで管理

以下のような2パターンの定義をuseStateで管理して配列の要素の追加、更新をしていきます。

「DrinkPattern1」はid, name, priceを持つオブジェクトです。使う時はこれを配列で定義します。

export type DrinkPattern1 = {
  id: string,
  name: string,
  price: number,
}

「DrinkPattern2」は「DrinkPattern1」とさほど変わりませんが内部で既に配列となっております。

export type DrinkPattern2 = {
  list: {
    id: string,
    name: string,
    price: number,
  }[]
}

実際の使い方としては下のようにuseStateで定義します。

const [drinkPattern1, setDrinkPattern1] = useState<DrinkPattern1[]>();

const [drinkPattern2, setDrinkPattern2] = useState<DrinkPattern2>();

「DrinkPattern1」のほうは参考にできるサイトも多いのでそこまで難しくはないですが、「DrinkPattern2」のほうがハマりました…。

ソース

import React, { useState } from "react";
import { DrinkPattern1 } from "./DrinkPattern1";
import { DrinkPattern2 } from "./DrinkPattern2";

const UseStateTest = () => {

  const [drinkPattern1, setDrinkPattern1] = useState<DrinkPattern1[]>(
    [
      {id: "01", name: "ビール", price: 400},
      {id: "02", name: "ワイン", price: 2200},
      {id: "03", name: "日本酒", price: 3000},
    ]
  );

  const [drinkPattern2, setDrinkPattern2] = useState<DrinkPattern2>(
    {
      list: [
        {id: "01", name: "ビール", price: 400},
        {id: "02", name: "ワイン", price: 2200},
        {id: "03", name: "日本酒", price: 3000},
      ]
    }
  );

  // drinkPattern1追加ボタンクリック
  const handlePt1Insert = () => {
    setDrinkPattern1([
      ...drinkPattern1, {id: "04", name: "焼酎", price: 1500}
    ]);
  };

  // drinkPattern1更新ボタンクリック
  const handlePt1Update = () => {
    setDrinkPattern1((preState) => {
      return preState.map((drink) => {
        if (drink.id == "02") {
          return {...drink, price: 50000};
        } else {
          return drink;
        }
      });
    });
  };

  // drinkPattern2追加ボタンクリック
  const handlePt2Insert = () => {
    setDrinkPattern2({
      ...drinkPattern2, list: [...drinkPattern2.list, {id: "04", name: "焼酎", price: 1500}]
    });
  };

  // drinkPattern2更新ボタンクリック
  const handlePt2Update = () => {
    setDrinkPattern2((preState) => {
      return {list:
        preState.list.map((drink) => {
          if (drink.id == "02") {
            return {...drink, price: 50000};
          } else {
            return drink;
          }
        })
      }
    })
  };

  return (
    <>
      <button onClick={handlePt1Insert}>drinkPattern1追加</button>
      <button onClick={handlePt1Update}>drinkPattern1更新</button>
      drinkPattern1の内容
      <div style={{marginBottom: 30}}>
        {JSON.stringify(drinkPattern1)}
      </div>

      <button onClick={handlePt2Insert}>drinkPattern2追加</button>
      <button onClick={handlePt2Update}>drinkPattern2更新</button>
      drinkPattern2の内容
      <div>
        {JSON.stringify(drinkPattern2)}
      </div>
    </>
  );
};
export default UseStateTest;

7行目、15行目:2パターンそれぞれをuseStateで定義し、初期値として同じ内容の配列を与えています。
25行目、32行目:drinkPattern1の配列に追加、更新をする処理です。
45行目、52行目:drinkPattern2の配列に追加、更新をする処理です。
67行目:結果を画面表示してます。

スプレッド構文(… ドット3つ)を理解していないと何をしているかわからないかもしれませんね。
正直なところ、書いた本人もわかりづらいです…。

動作確認

まずはボタンをクリックする前の初期表示の状態です。

drinkPattern1追加ボタン、drinkPattern2追加ボタンをクリックしてみます。

2パターンそれぞれに「焼酎」の要素が追加されました。

次に画面を初期化して今度はdrinkPattern1更新ボタン、drinkPattern2更新ボタンをクリックしてみます。

2パターンそれぞれで「ワイン」の「price」が「50000」に変更されました。

以上となります。

ここまでお読みいただきありがとうございました。

React

Posted by だゆう