2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactとバックエンドで作る!実践Web開発入門 | 第5章: Reactの状態管理を強化

Posted at

はじめに

第4章でReactとバックエンドを連携しました。今回は、アプリが複雑になるにつれて必要となる「状態管理」を強化します。具体的には、Context APIを使って商品リストをグローバルに管理する方法を学びます。

目標

  • Context APIの基本を理解する
  • グローバルな状態を管理する
  • 商品追加機能を追加する

Context APIとは

Context APIは、Reactでコンポーネント間でデータを簡単に共有するための仕組みです。Propsを何層も渡す必要がなくなり、コードがシンプルになります。

Contextの作成

frontend/srcProductContext.tsxを作成し、以下を追加:

import React, { createContext, useState, useContext } from 'react';

const ProductContext = createContext();

export const ProductProvider = ({ children }) => {
  const [products, setProducts] = useState([]);

  const addProduct = (newProduct) => {
    setProducts((prev) => [...prev, { ...newProduct, id: Date.now() }]);
  };

  return (
    <ProductContext.Provider value={{ products, setProducts, addProduct }}>
      {children}
    </ProductContext.Provider>
  );
};

export const useProductContext = () => useContext(ProductContext);

Appコンポーネントの更新

App.tsxを以下のように修正し、Contextを利用:

import React, { useEffect } from 'react';
import './App.css';
import { ProductProvider, useProductContext } from './ProductContext';

function App() {
  return (
    <ProductProvider>
      <div className="App">
        <Header />
        <ProductList />
        <Footer />
      </div>
    </ProductProvider>
  );
}

const Header = () => (
  <header>
    <h1>商品リスト</h1>
  </header>
);

const ProductList = () => {
  const { products, setProducts, addProduct } = useProductContext();
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState(null);
  const [newProduct, setNewProduct] = React.useState({ name: '', price: '' });

  useEffect(() => {
    const fetchProducts = async () => {
      try {
        const response = await fetch('http://localhost:5000/products');
        if (!response.ok) throw new Error('データの取得に失敗しました');
        const data = await response.json();
        setProducts(data);
      } catch (err) {
        setError(err.message);
      } finally {
        setLoading(false);
      }
    };

    fetchProducts();
  }, [setProducts]);

  const handleAddProduct = (e) => {
    e.preventDefault();
    if (newProduct.name && newProduct.price) {
      addProduct({ name: newProduct.name, price: Number(newProduct.price) });
      setNewProduct({ name: '', price: '' });
    }
  };

  if (loading) return <main>読み込み中...</main>;
  if (error) return <main>エラー: {error}</main>;

  return (
    <main>
      <h2>商品一覧</h2>
      <form onSubmit={handleAddProduct}>
        <input
          type="text"
          placeholder="商品名"
          value={newProduct.name}
          onChange={(e) => setNewProduct({ ...newProduct, name: e.target.value })}
        />
        <input
          type="number"
          placeholder="価格"
          value={newProduct.price}
          onChange={(e) => setNewProduct({ ...newProduct, price: e.target.value })}
        />
        <button type="submit">追加</button>
      </form>
      <ul>
        {products.map((product) => (
          <ProductItem key={product.id} name={product.name} price={product.price} />
        ))}
      </ul>
    </main>
  );
};

const ProductItem = ({ name, price }) => (
  <li>
    {name} - {price}</li>
);

const Footer = () => (
  <footer>
    <p>© 2025 React Web開発入門</p>
  </footer>
);

export default App;

CSSの調整

App.cssにフォーム用のスタイルを追加:

form {
  margin: 20px 0;
}

input {
  padding: 5px;
  margin-right: 10px;
}

button {
  padding: 5px 10px;
  background-color: #61dafb;
  border: none;
  cursor: pointer;
}

button:hover {
  background-color: #21a1f1;
}

動作確認

  1. バックエンドを起動(node index.js)。
  2. フロントエンドを起動(npm start)。
  3. http://localhost:3000で確認。商品リストが表示され、フォームで新しい商品を追加できます。
  • 注意: 今回は追加した商品はバックエンドに保存されません(次章で対応)。

次回予告

第6章では、バックエンドにデータベースを追加し、商品データを永続的に保存する方法を学びます。お楽しみに!


この記事が役に立ったら、ぜひ「いいね」や「ストック」をお願いします!質問や感想はコメント欄で気軽にどうぞ。次回も一緒に学びましょう!

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?