useState フックでデータを更新する Provider と Consumer を実装する

この記事では「React Context API を使う簡単な例」から「useState フックを用いてステートにデータを置く」にかけて作ったプログラムを変更して、 ステートに保存したデータを更新可能にします。

このプログラムは、リスト内のアイテムをクリックすると削除でき、Add ボタンをクリックすると Fruit 番号 というアイテムが追加されるという動きとします。

Provider に state 更新用のメソッドを渡す

前回の記事「useState フックを用いてステートにデータを置く」では、useState フックを用いて state にデータをセットしました。

これを発展させて、データを更新できるようにしましょう。

FruitContext.jsを次のように変更します。

import React, { createContext, useState } from 'react';
import { fruitData } from './fruit-data';

const FruitContext = createContext();

export const FruitProvider = ({ children }) => {
  const [fruits, setFruits] = useState(fruitData);
  const addFruit = (newFruit) => setFruits([...fruits, newFruit]);
  const removeFruit = (s) => setFruits(fruits.filter((fruit) => fruit !== s));

  return (
    <FruitContext.Provider value={{ fruits, addFruit, removeFruit }}>
      {children}
    </FruitContext.Provider>
  );
};

export const FruitConsumer = FruitContext.Consumer;

useState フックは state の初期値を受け取り、 「state の値を保持する変数」と「state を更新する関数」を要素に持つ配列を返します。

7 行目では、useState フックが返す配列のひとつ目の要素 (つまり「state の値を保持する変数」) を fruitsに、 二つ目の要素 (つまり「state を更新する関数」) を setFruits という名前の定数にセットしています。

8-9 行目では、setFruits関数を用いて、addFruits 関数と removeFruit 関数を実装しています。

12 行目で Provider の value プロパティに、fruits (データ) の他に、state 更新用の関数、つまり addFruitremoveFruit を渡しています。

これによって、Consumer 側で state データ以外に、データ更新用のメソッドを取り出すことができます。

データ更新可能な Consumer の実装

Provider 側でデータ更新用の関数を渡しているので、Consumer 側でそれを利用するのは簡単です。

App.js は次のようになります。

import React from 'react';
import './App.css';
import { FruitConsumer } from './FruitContext';

function App() {
  return (
    <FruitConsumer>
      {(value) => {
        const { fruits, addFruit, removeFruit } = value;
        return (
          <>
            <h1>Fruits</h1>
            <div>
              <button onClick={() => addFruit(`Fruit ${fruits.length + 1}`)}>
                Add
              </button>
            </div>
            <ul>
              {fruits.map((fruit, i) => (
                <li key={i} onClick={() => removeFruit(fruit)}>
                  {fruit}
                </li>
              ))}
            </ul>
          </>
        );
      }}
    </FruitConsumer>
  );
}

export default App;

9 行目で Provider が渡す value から、state のデータ fruits の他に、 addFruit 関数、removeFruit 関数を受け取っています。

JavaScript の復習

Provider でデータを渡す側はショートハンドプロパティ、Consumer で受け取る側は分割代入です。どちらも React の機能ではなく JavaScript (ES6+) のシンタックスです。 React 固有のシンタックスではありません。丸暗記にならないように気を付けましょう。

14 行目では新しく追加したボタン要素の、クリックハンドラで addFruit 関数を呼び出しています。

20 行目ではリストアイテムのクリックハンドラで、クリックしたアイテムと同じ名前の要素を、state データの配列の中でフィルターして削除しています。

以上で、データの更新を行うことができました。

これで動作は問題ないのですが、さらに useContext フックを用いることで、コンスーマはもっと簡略化できます。 useContext を用いた例は「useContext フックで Consumer をリファクタリングする」で説明します。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 React 入門