HTML、CSS、JavaScriptReactの基礎

【React】コンポーネント開発(Props,State)を解説

Reactコンポーネント開発(props,state)解説ページのアイキャッチ画像 HTML、CSS、JavaScript

本記事は、Reactアプリケーション開発の基礎となる重要な概念を網羅的に解説しています。PropsとStateの違いを明確にし、条件分岐と繰り返し処理の実装方法、さらには高度なイベント処理技術まで紹介します。

はじめに

Reactの基礎の記事一覧はクリックすると表示されます。

Reactは、Node.jsが必要です。インストールがまだの方はこちらを確認してください。

開発環境は、VSCodeがおすすめです。

コンポーネントを支える基本概念(Props,State)

Props

Propsは親コンポーネントから子コンポーネントにデータを渡すための仕組みです。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
// アプリケーションのスタイルシートをインポート
import "./App.css";

// Greetingコンポーネントの定義
// propsを引数として受け取り、nameプロパティを使用
function Greeting(props) {
  // propsから渡されたnameを使用して挨拶メッセージを返す
  return <h1>Hello, {props.name}!</h1>;
}

// Appコンポーネントの定義(アプリケーションのメインコンポーネント)
function App() {
  return (
    // Appコンポーネントのルート要素
    <div className="App">
      {/* Greetingコンポーネントを2回使用、異なる名前を渡す */}
      <Greeting name="Alice" />
      <Greeting name="Bob" />
    </div>
  );
}

// Appコンポーネントをデフォルトエクスポート
// これにより他のファイルでインポートして使用可能になる
export default App;

出力結果:

  1. import
    • App.cssをインポートしています。これはアプリケーションのスタイルを定義するCSSファイルです。
    • このファイルには、アプリケーション全体に適用されるスタイルが記述されていると想定されます。
  2. Greeting コンポーネント
    • Greetingは関数コンポーネントです。
    • propsを引数として受け取ります。これは、このコンポーネントに渡される全てのプロパティを含むオブジェクトです。
    • props.nameを使用して、渡された名前を挨拶文に組み込んでいます。
    • <h1>タグを使用して、大見出しとして挨拶文を表示します。
    • {props.name}の部分では、JavaScriptの式を JSX 内に埋め込んでいます。
  3. App コンポーネント
    • Appはアプリケーションのメインコンポーネントです。
    • <div className="App">は、このコンポーネントのルート要素です。className属性はCSSクラスを指定するために使用されます。
    • <Greeting name="Alice" /><Greeting name="Bob" />は、Greetingコンポーネントを2回使用しています。
    • それぞれのGreetingコンポーネントに異なるnameプロパティを渡しています。
  4. export
    • Appコンポーネントをデフォルトエクスポートしています。これにより、他のファイルでこのコンポーネントを簡単にインポートできます。

動作の流れ:

  1. アプリケーションが起動し、Appコンポーネントがレンダリングされます。
  2. Appコンポーネント内で2つのGreetingコンポーネントがレンダリングされます。
  3. 1つ目のGreetingコンポーネントはname="Alice"というプロパティを受け取ります。
  4. 2つ目のGreetingコンポーネントはname="Bob"というプロパティを受け取ります。
  5. Greetingコンポーネントは、受け取ったnameプロパティを使用して挨拶文を生成します。
  6. 画面に「Hello, Alice!」と「Hello, Bob!」という2つの挨拶文が表示されます。
  7. これらの挨拶文は<h1>タグで囲まれているため、大きな見出しとして表示されます。
  8. App.cssで定義されたスタイルが、全体のレイアウトに適用されます。

このコードは、Reactの基本的な概念である「コンポーネント」と「props」を示しています。Greetingコンポーネントは再利用可能で、異なるプロパティ(この場合は名前)を渡すことで、異なる出力を生成できます。これはReactの特徴の一つで、コードの再利用性と保守性を高めます。

State

Stateはコンポーネント内で管理される可変データです。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
// React本体とuseStateフックをインポート
import React from "react";
// アプリケーションのスタイルシートをインポート
import "./App.css";

// Counterコンポーネントの定義
function Counter() {
  // useStateフックを使用して状態を初期化
  // count: 現在のカウント値、setCount: カウントを更新する関数
  const [count, setCount] = React.useState(0);

  return (
    <div>
      {/* 現在のカウント値を表示 */}
      <p>You clicked {count} times</p>
      {/* ボタンクリック時にカウントを増加させる */}
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

// Appコンポーネントの定義(アプリケーションのメインコンポーネント)
function App() {
  return (
    <div className="App">
      {/* Counterコンポーネントを表示 */}
      <Counter />
    </div>
  );
}

// Appコンポーネントをデフォルトエクスポート
export default App;

出力結果(初期状態):

ボタンをクリックするたびに、カウントが増加します。例えば、3回クリックした後:

  1. import
    • Reactをインポートしています。これはReactの基本機能を使うために必要です。
    • App.cssをインポートしています。これはアプリケーションのスタイルを定義するCSSファイルです。
  2. Counter コンポーネント
    • Counterは関数コンポーネントです。
    • React.useState(0)を使用してcountという状態変数を作成し、初期値を0に設定しています。
    • setCountcountの値を更新するための関数です。
    • コンポーネントは現在のcount値を表示するパラグラフと、クリックでカウントを増やすボタンをレンダリングします。
    • ボタンがクリックされると、setCount(count + 1)が呼び出され、countの値が1増加します。
  3. App コンポーネント
    • Appはアプリケーションのメインコンポーネントです。
    • Counterコンポーネントをレンダリングしています。
    • className="App"は、このdiv要素にCSSクラスを適用するために使用されます。
  4. export
    • Appコンポーネントをデフォルトエクスポートしています。これにより、他のファイルでこのコンポーネントを簡単にインポートできます。

動作の流れ:

  1. アプリケーションが起動し、Appコンポーネントがレンダリングされます。
  2. Appコンポーネント内でCounterコンポーネントがレンダリングされます。
  3. Counterコンポーネントが初期化され、countの初期値が0に設定されます。
  4. 画面に「You clicked 0 times」というテキストと「Click me」ボタンが表示されます。
  5. ユーザーが「Click me」ボタンをクリックします。
  6. setCount(count + 1)が呼び出され、countの値が1増加します。
  7. Reactが状態の変更を検知し、Counterコンポーネントを再レンダリングします。
  8. 更新されたcount値(1)が画面に反映され、「You clicked 1 times」と表示されます。
  9. 5-8のステップがボタンがクリックされるたびに繰り返されます。

このように、Reactの状態管理と再レンダリングの仕組みを使って、ユーザーのインタラクションに応じて動的にUIを更新する簡単なカウンターアプリケーションが実現されています。

PropsとStateの違い

  1. データの流れ: Propsは親から子へ、Stateはコンポーネント内で管理します。
  2. 変更可能性: Propsは読み取り専用、Stateは変更可能です。
  3. 再レンダリング: Stateが変更されると、そのコンポーネントが自動的に再レンダリングされます。

これらの概念を適切に使用することで、効率的で再利用可能なReactアプリケーションを構築できます。Propsを使ってコンポーネント間でデータを受け渡し、Stateを使ってコンポーネント内の動的なデータを管理することで、柔軟で保守性の高いUIを作成できます。

条件分岐と繰り返し処理

Reactでの条件分岐と繰り返し処理の実装方法を解説します。

条件分岐

条件に応じて異なる内容を表示したい場合、三項演算子や論理演算子を使用します。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
import React from 'react';
import './App.css';

// ユーザーがログインしている場合のグリーティングコンポーネント
function UserGreeting() {
  return <h1>Welcome back, User!</h1>;
}

// ゲスト(未ログイン)ユーザー向けのグリーティングコンポーネント
function GuestGreeting() {
  return <h1>Welcome, Guest. Please sign in.</h1>;
}

// isLoggedIn プロップに基づいて適切なグリーティングを表示するコンポーネント
function Greeting({ isLoggedIn }) {
  return (
    <div>
      {/* 
        三項演算子を使用した条件分岐
        isLoggedIn が true の場合は UserGreeting を、
        false の場合は GuestGreeting を表示
      */}
      {isLoggedIn ? <UserGreeting /> : <GuestGreeting />}
    </div>
  );
}

// アプリケーションのメインコンポーネント
function App() {
  // ログイン状態を管理するための状態変数
  const [isLoggedIn, setIsLoggedIn] = React.useState(false);

  return (
    <div className="App">
      {/* Greeting コンポーネントに isLoggedIn 状態を渡す */}
      <Greeting isLoggedIn={isLoggedIn} />
      
      {/* ログイン状態を切り替えるボタン */}
      <button onClick={() => setIsLoggedIn(!isLoggedIn)}>
        {isLoggedIn ? 'Logout' : 'Login'}
      </button>
    </div>
  );
}

export default App;

出力結果:

isLoggedInfalseの場合:

isLoggedIntrueの場合:

  1. UserGreeting コンポーネント
    • このコンポーネントは、ログインしているユーザー向けのメッセージを表示します。
  2. GuestGreeting コンポーネント
    • このコンポーネントは、ログインしていないゲストユーザー向けのメッセージを表示します。
  3. Greeting コンポーネント
    • isLoggedInというプロップ(属性)を受け取り、その値に基づいて適切なグリーティングを表示します。
    • {isLoggedIn ? <UserGreeting /> : <GuestGreeting />} は三項演算子を使用した条件分岐です。
    • isLoggedIntrueの場合は<UserGreeting />を、falseの場合は<GuestGreeting />を表示します。
  4. App コンポーネント
    • このコンポーネントはアプリケーションのメインコンポーネントです。
    • React.useState(false)を使用してisLoggedInという状態変数を作成し、初期値をfalseに設定しています。
    • setIsLoggedInisLoggedInの値を更新するための関数です。
    • <Greeting isLoggedIn={isLoggedIn} />で、現在のログイン状態をGreetingコンポーネントに渡しています。
    • ボタンをクリックすると、setIsLoggedIn(!isLoggedIn)が呼び出され、isLoggedInの値が反転します(trueならfalseに、falseならtrueに)。
    • ボタンのテキストもisLoggedInの値に応じて変化します。

動作の流れ:

  1. アプリが起動すると、初期状態ではisLoggedInfalseなので、”Welcome, Guest. Please sign in.”というメッセージと”Login”ボタンが表示されます。
  2. “Login”ボタンをクリックすると、setIsLoggedIn(!isLoggedIn)が実行され、isLoggedIntrueになります。
  3. isLoggedIntrueになったので、表示が”Welcome back, User!”に変わり、ボタンのテキストも”Logout”に変わります。
  4. “Logout”ボタンをクリックすると、再びisLoggedInfalseになり、元の状態に戻ります。

このように、Reactの状態管理(useState)と条件分岐(三項演算子)を使用することで、ユーザーの操作に応じて動的にUIを変更することができます。これはReactアプリケーションの基本的な動作パターンの一つです。

繰り返し処理

配列の要素を繰り返し処理する場合、map関数を使用します。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
import React from 'react';
import './App.css';

// 数字のリストを表示するコンポーネント
function NumberList({ numbers }) {
  return (
    <ul>
      {/* 
        numbers配列の各要素に対してmap関数を使用
        各数字に対して<li>要素を生成
      */}
      {numbers.map((number) =>
        // keyプロパティに一意の値を設定(ここでは数字自体を文字列化)
        <li key={number.toString()}>
          {number}
        </li>
      )}
    </ul>
  );
}

// アプリケーションのメインコンポーネント
function App() {
  // 表示する数字の配列
  const numbers = [1, 2, 3, 4, 5];

  return (
    <div className="App">
      <h1>Number List</h1>
      {/* NumberListコンポーネントにnumbers配列を渡す */}
      <NumberList numbers={numbers} />
    </div>
  );
}

export default App;

出力結果:

  1. NumberList コンポーネント
    • NumberListは関数コンポーネントで、numbers配列をプロップスとして受け取ります。
    • <ul>タグ内でnumbers.map()を使用して、各数字に対して<li>要素を生成します。
    • key={number.toString()}は、Reactが各リスト項目を一意に識別するために使用します。
    • <li>要素の中に数字そのものが表示されます。
  2. App コンポーネント
    • Appはアプリケーションのメインコンポーネントです。
    • numbers配列を定義し、表示する数字のリストを設定しています。
    • <h1>タグでタイトル「Number List」を表示します。
    • <NumberList numbers={numbers} />NumberListコンポーネントを使用し、numbers配列をプロップスとして渡しています。

動作の流れ:

  1. アプリケーションが起動し、Appコンポーネントがレンダリングされます。
  2. Appコンポーネント内でnumbers配列[1, 2, 3, 4, 5]が定義されます。
  3. Appコンポーネントが「Number List」というタイトルを<h1>タグでレンダリングします。
  4. AppコンポーネントがNumberListコンポーネントをレンダリングし、numbers配列をpropsとして渡します。
  5. NumberListコンポーネントがnumbers配列を受け取ります。
  6. NumberListコンポーネントが<ul>タグを作成します。
  7. numbers.map()が実行され、配列の各数字に対して以下の処理が行われます:
    • <li>要素が作成されます。
    • <li>要素にkeyプロパティが設定されます。
    • <li>要素の中に数字が表示されます。
  8. 最終的に、画面には「Number List」というタイトルの下に、1から5までの数字がリスト形式で表示されます。

このコードは、Reactの重要な概念である「リストのレンダリング」と「keyプロパティの使用」を示しています。map()関数を使用して配列データを動的にレンダリングする方法と、各リスト項目に一意のキーを提供することの重要性を学ぶことができます。

高度なイベント処理

Reactでのイベント処理の応用テクニックを紹介します。

イベントハンドラの最適化

Reactでは、パフォーマンスを向上させるためにuseCallbackフックを使用してイベントハンドラを最適化できます。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
// React本体とuseCallbackフックをインポート
import React, { useCallback } from 'react';
import './App.css';

// 最適化されたボタンコンポーネント
function OptimizedButton() {
  // useCallbackを使用してクリックハンドラを最適化
  const handleClick = useCallback(() => {
    console.log('Clicked!');
  }, []); // 空の依存配列は、この関数が再レンダリング時に再生成されないことを意味する

  return <button onClick={handleClick}>Click me</button>;
}

// アプリケーションのメインコンポーネント
function App() {
  return (
    <div className="App">
      <h1>Optimized Button Example</h1>
      {/* 最適化されたボタンコンポーネントを使用 */}
      <OptimizedButton />
    </div>
  );
}

export default App;

出力結果:

ボタンをクリックするたびに、コンソールに以下が表示されます:

※ブラウザを開いた状態で、F12でコンソール画面が表示されます。

  1. import
    • Reactをインポートしています。これはReactの基本機能を使うために必要です。
    • useCallbackフックをReactからインポートしています。これは関数の最適化に使用されます。
    • App.cssをインポートしています。これはアプリケーションのスタイルを定義するCSSファイルです。
  2. OptimizedButton コンポーネント
    • OptimizedButtonは関数コンポーネントです。
    • useCallbackフックを使用してhandleClick関数を最適化しています。
    • useCallbackの第一引数は最適化したい関数で、第二引数は依存配列です。
    • 空の依存配列[]は、この関数がコンポーネントの再レンダリング時に再生成されないことを意味します。
    • handleClick関数は、クリック時に’Clicked!’をコンソールに出力します。
    • コンポーネントは「Click me」というテキストを持つボタンをレンダリングし、クリックイベントにhandleClick関数を割り当てています。
  3. App コンポーネント
    • Appはアプリケーションのメインコンポーネントです。
    • <h1>タグでタイトル「Optimized Button Example」を表示しています。
    • <OptimizedButton />OptimizedButtonコンポーネントを使用しています。

動作の流れ:

  1. アプリケーションが起動し、Appコンポーネントがレンダリングされます。
  2. Appコンポーネントが「Optimized Button Example」というタイトルを<h1>タグでレンダリングします。
  3. AppコンポーネントがOptimizedButtonコンポーネントをレンダリングします。
  4. OptimizedButtonコンポーネント内で、useCallbackフックを使用してhandleClick関数が最適化されます。
  5. OptimizedButtonコンポーネントが「Click me」というテキストを持つボタンをレンダリングします。
  6. ユーザーがボタンをクリックすると、handleClick関数が実行され、コンソールに「Clicked!」と出力されます。
  7. コンポーネントが再レンダリングされても(例えば、親コンポーネントの状態が変更された場合)、handleClick関数は再生成されません。

このコードは、ReactのuseCallbackフックを使用して関数の最適化を行う方法を示しています。useCallbackを使用することで、不要な再レンダリングを防ぎ、アプリケーションのパフォーマンスを向上させることができます。これは特に、大規模なアプリケーションや、頻繁に再レンダリングが発生する可能性のあるコンポーネントで重要です。

カスタムイベント

コンポーネント間の通信を行うために、カスタムイベントを作成できます。

App.jsの内容をすべて削除して、以下の内容をコピペして保存します。

JSX
// React本体をインポート
import React from 'react';
import './App.css';

// Childコンポーネントの定義
function Child({ onCustomEvent }) {
  return (
    <button onClick={() => onCustomEvent('Hello from Child')}>
      Trigger Custom Event
    </button>
  );
}

// Parentコンポーネントの定義
function Parent() {
  // カスタムイベントのハンドラ関数
  const handleCustomEvent = (data) => {
    console.log('Custom event triggered:', data);
  };

  return <Child onCustomEvent={handleCustomEvent} />;
}

// アプリケーションのメインコンポーネント
function App() {
  return (
    <div className="App">
      <h1>Custom Event Example</h1>
      {/* Parentコンポーネントを使用 */}
      <Parent />
    </div>
  );
}

export default App;

出力結果:

ボタンをクリックすると、コンソールに以下が表示されます:

  1. Child コンポーネント
    • Childは関数コンポーネントです。
    • onCustomEventというプロップを受け取ります。これは親コンポーネントから渡される関数です。
    • ボタンをレンダリングし、クリックイベントに関数を割り当てています。
    • ボタンがクリックされると、onCustomEvent関数が’Hello from Child’という文字列を引数として呼び出されます。
  2. Parent コンポーネント
    • Parentは関数コンポーネントです。
    • handleCustomEvent関数を定義しています。この関数は引数として受け取ったデータをコンソールに出力します。
    • Childコンポーネントをレンダリングし、onCustomEventプロップとしてhandleCustomEvent関数を渡しています。
  3. App コンポーネント
    • Appはアプリケーションのメインコンポーネントです。
    • <h1>タグでタイトル「Custom Event Example」を表示しています。
    • <Parent />Parentコンポーネントを使用しています。

動作の流れ:

  1. アプリケーションが起動し、Appコンポーネントがレンダリングされます。
  2. Appコンポーネントが「Custom Event Example」というタイトルを<h1>タグでレンダリングします。
  3. AppコンポーネントがParentコンポーネントをレンダリングします。
  4. ParentコンポーネントがhandleCustomEvent関数を定義します。
  5. ParentコンポーネントがChildコンポーネントをレンダリングし、onCustomEventプロップとしてhandleCustomEvent関数を渡します。
  6. Childコンポーネントが「Trigger Custom Event」というテキストを持つボタンをレンダリングします。
  7. ユーザーがボタンをクリックすると:
    • Childコンポーネント内のonClickハンドラが実行されます。
    • onCustomEvent('Hello from Child')が呼び出されます。
    • これは実際にはParentコンポーネントのhandleCustomEvent関数を呼び出します。
    • handleCustomEvent関数がコンソールに「Custom event triggered: Hello from Child」と出力します。

このコードは、Reactにおける「props」を使用した親子コンポーネント間のコミュニケーション方法を示しています。子コンポーネント(Child)から親コンポーネント(Parent)にデータを渡す、いわゆる「カスタムイベント」の実装方法を学ぶことができます。これは、コンポーネント間でデータや動作を共有する上で非常に重要な概念です。

まとめ

  • PropsStateは、Reactコンポーネントのデータ管理の基本となる概念です。Propsは親コンポーネントから渡されるデータ、Stateはコンポーネント内で管理される可変データです。
  • 条件分岐と繰り返し処理は、動的なUIを構築する上で重要な技術です。JSXでの条件付きレンダリングや配列のマッピングを使用して実装します。
  • イベント処理の最適化は、Reactアプリケーションのパフォーマンス向上に寄与します。カスタムイベントの使用により、コンポーネント間の通信をより柔軟に行うことができます。
  • PropsとStateの適切な使い分けにより、コンポーネントの再利用性保守性が向上します。
  • 条件分岐と繰り返し処理を効果的に使用することで、データ駆動型のUIを簡潔に実装できます。

Reactの基本概念を理解し、適切に活用することで、より効率的柔軟なアプリケーション開発が可能になります。特に、PropsとStateの概念は、コンポーネントベースのアーキテクチャの根幹をなすものであり、これらを適切に使い分けることがReact開発の鍵となります。

継続的な学習と実践を通じて、これらの概念と技術を深く理解し、応用することが、高品質なReactアプリケーション開発への近道となるでしょう。

コメント

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