Udemyセール!最大95%オフ!1,200円~Udemy公式サイト >

この記事にはプロモーションが含まれています。

【React】コンポーネントとJSXの理解|TODOアプリ【基本編:第2回】

【React】コンポーネントとJSXの理解|TODOアプリ【基本編:第2回】

Reactで作るTODOアプリ開発シリーズ第2回

この記事では

ReactのコンポーネントとJSX

について詳しく学習していきます。

前回は、Reactの基礎知識と開発環境の構築について学習しました。今回は、Reactの核となるコンポーネントとJSXについて、より深く理解していきましょう。

コンポーネントベース開発は、Reactの最大の特徴の一つです。小さな部品を組み合わせて大きなアプリケーションを作ることで、コードの再利用性と保守性を大幅に向上させることができます。

この記事でわかること
  • コンポーネントの概念と種類(関数コンポーネント、クラスコンポーネント)
  • JSXの詳細な文法と特徴
  • Propsの受け渡し方法
  • コンポーネントの分割と再利用
  • 簡単なTODOアイテムコンポーネントの作成
ケケンタ

コンポーネントベース開発の考え方を理解することで、より効率的で保守性の高いアプリケーションを作ることができるようになります!

TODOアプリ(第2回:完成イメージ)
TODOアプリ(第2回:完成イメージ)

TODOアプリ開発シリーズのまとめ記事はこちら




ケケンタ

ケケンタのITブログでは、WebアプリPHPLaravel)やWeb制作WordPressコーディング)について情報を発信しています。
学習中の方や実務をされている方など多くの方にアクセスいただいていますので、ぜひほかの記事も参考にしてみてください!


運動不足、気になっていませんか?

もしプログラミング学習やお仕事で運動不足が気になっているなら

連続屈伸運動がおすすめです!

ボタンにカーソルを合わせるだけ
カウントダウンが始まるタイマーをご用意してみました!

ケケンタ

無理のない範囲で、ぜひ隙間時間に屈伸運動を取り入れてみて下さい!

タイマースタート

3:00

※運動不足だと連続3分で取り組んでもかなり息が切れます
(僕は加えて気分もちょっと悪くなりました……)
絶対にご無理の無い範囲でお取り組みください!



目次

前回までのコード

第1回で作成したコードを確認しましょう。以下のファイル構成になっています。

ファイル構造

todo-app/
├── src/
│   ├── App.js
│   ├── App.css
│   ├── TodoItem.js
│   └── index.js

App.js

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

function App() {
  return (
    <div className="App">
      <h1>React TODOアプリ</h1>
      <div className="todo-list">
        <TodoItem text="Reactを学ぶ" completed={false} />
        <TodoItem text="TODOアプリを作る" completed={true} />
        <TodoItem text="データベース連携" completed={false} />
      </div>
    </div>
  );
}

export default App;

TodoItem.js

import React from 'react';

function TodoItem({ text, completed }) {
  return (
    <div className="todo-item">
      <input 
        type="checkbox" 
        checked={completed} 
        readOnly 
      />
      <span style={{ 
        textDecoration: completed ? 'line-through' : 'none' 
      }}>
        {text}
      </span>
    </div>
  );
}

export default TodoItem;

App.css

.App {
  text-align: center;
  padding: 20px;
  max-width: 600px;
  margin: 0 auto;
}

.todo-list {
  margin-top: 20px;
}

.todo-item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px;
  border-bottom: 1px solid #eee;
}

.todo-item input[type="checkbox"] {
  margin-right: 10px;
}

.todo-item span {
  font-size: 16px;
}

コンポーネントの概念

実際に手を動かす前に、まずは必要な知識について解説をしていきます。

Reactのコンポーネントは、UIを構成する独立した部品です。HTMLの要素を拡張したようなもので、独自のロジックとスタイルを持つことができます。

コンポーネントの種類

Reactには主に2種類のコンポーネントがあります:

1. 関数コンポーネント(Function Component)

現在のReactでは、関数コンポーネントが推奨されています。シンプルで理解しやすく、Hooksを使用して状態管理も行えます。

function Welcome({ name }) {
  return <h1>Hello, {name}!</h1>;
}

2. クラスコンポーネント(Class Component)

こちらは従来の書き方で、現在は関数コンポーネントが主流ですが、理解しておくと良いでしょう。

class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

JSXの詳細な文法ルール

JSXは、JavaScriptの中にHTMLライクな記法を書くことができるReactの拡張構文です。

1. 要素のネスト

JSXでは、複数の要素を返す場合は、必ず1つの親要素で囲む必要があります。

// ❌ エラー:複数の要素を直接返している
function App() {
  return (
    <h1>タイトル</h1>
    <p>説明文</p>
  );
}

// ✅ 正しい:1つの親要素で囲んでいる
function App() {
  return (
    <div>
      <h1>タイトル</h1>
      <p>説明文</p>
    </div>
  );
}

// ✅ Fragmentを使用する方法(推奨)
function App() {
  return (
    <>
      <h1>タイトル</h1>
      <p>説明文</p>
    </>
  );
}

2. JavaScript式の埋め込み

JSXの中では、{}を使ってJavaScriptの式を埋め込むことができます。

function App() {
  const name = "React";
  const isLoggedIn = true;
  const items = ["アイテム1", "アイテム2", "アイテム3"];

  return (
    <div>
      <h1>Hello, {name}!</h1>
      <p>{isLoggedIn ? "ログイン中" : "ログアウト中"}</p>
      <ul>
        {items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    </div>
  );
}

3. 属性の書き方

JSXでは、HTMLの属性名が少し異なります。

function App() {
  const className = "container";
  const style = { backgroundColor: "blue", color: "white" };

  return (
    <div 
      className={className}  // classではなくclassName
      style={style}         // オブジェクトとして渡す
      data-testid="app"     // カスタム属性はそのまま
    >
      コンテンツ
    </div>
  );
}

Propsの受け渡し

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

Propsの基本

// 親コンポーネント
function App() {
  return (
    <div>
      <TodoItem text="買い物に行く" completed={false} priority="high" />
      <TodoItem text="本を読む" completed={true} priority="low" />
    </div>
  );
}

// 子コンポーネント
function TodoItem({ text, completed, priority }) {
  return (
    <div className={`todo-item priority-${priority}`}>
      <input type="checkbox" checked={completed} readOnly />
      <span style={{ textDecoration: completed ? 'line-through' : 'none' }}>
        {text}
      </span>
    </div>
  );
}

デフォルト値の設定

Propsにデフォルト値を設定することで、値が渡されなかった場合の処理を書くことができます。

function TodoItem({ text, completed = false, priority = "medium" }) {
  return (
    <div className={`todo-item priority-${priority}`}>
      <input type="checkbox" checked={completed} readOnly />
      <span style={{ textDecoration: completed ? 'line-through' : 'none' }}>
        {text}
      </span>
    </div>
  );
}

style属性の指定にはjavascriptの三項演算子を利用して条件分岐しています。

スプレッド構文の使用

スプレッド構文を使用することで、オブジェクトのプロパティを展開して渡すことができます。

function App() {
  const todoData = {
    text: "買い物に行く",
    completed: false,
    priority: "high",
    createdAt: "2024-01-01"
  };

  return (
    <div>
      <TodoItem {...todoData} />
    </div>
  );
}

【実践】コンポーネントの分割と再利用

それでは、ここからは実際に手を動かして、新しいコンポーネントを作成していきましょう。

大きなコンポーネントを小さな部品に分割することで、コードの再利用性と保守性を向上させることができます。

1. TodoListコンポーネントの作成

src/TodoList.jsファイルを新規作成し、以下のコードを記述してください。

import React from 'react';
import TodoItem from './TodoItem';

function TodoList({ todos }) {
  return (
    <div className="todo-list">
      {todos.map((todo, index) => (
        <TodoItem 
          key={index}
          text={todo.text}
          completed={todo.completed}
          priority={todo.priority}
        />
      ))}
    </div>
  );
}

export default TodoList;

2. TodoHeaderコンポーネントの作成

src/TodoHeader.jsファイルを新規作成し、以下のコードを記述してください。

import React from 'react';

function TodoHeader({ title, totalCount, completedCount }) {
  return (
    <div className="todo-header">
      <h1>{title}</h1>
      <div className="todo-stats">
        <span>総数: {totalCount}</span>
        <span>完了: {completedCount}</span>
        <span>未完了: {totalCount - completedCount}</span>
      </div>
    </div>
  );
}

export default TodoHeader;

3. App.jsの修正

既存のsrc/App.jsを以下のように修正してください。

import React from 'react';
import './App.css';
import TodoHeader from './TodoHeader';
import TodoList from './TodoList';

function App() {
  const todos = [
    { text: "Reactを学ぶ", completed: false, priority: "high" },
    { text: "TODOアプリを作る", completed: true, priority: "medium" },
    { text: "データベース連携", completed: false, priority: "low" },
    { text: "デプロイする", completed: false, priority: "medium" }
  ];

  const completedCount = todos.filter(todo => todo.completed).length;

  return (
    <div className="App">
      <TodoHeader 
        title="React TODOアプリ"
        totalCount={todos.length}
        completedCount={completedCount}
      />
      <TodoList todos={todos} />
    </div>
  );
}

export default App;

4. スタイルの追加

既存のsrc/App.cssに以下のスタイルを追加してください。

.todo-header {
  margin-bottom: 30px;
}

.todo-stats {
  display: flex;
  justify-content: center;
  gap: 20px;
  margin-top: 10px;
  font-size: 14px;
  color: #666;
}

.todo-stats span {
  padding: 5px 10px;
  background-color: #f5f5f5;
  border-radius: 15px;
}

.priority-high {
  border-left: 4px solid #ff4757;
}

.priority-medium {
  border-left: 4px solid #ffa502;
}

.priority-low {
  border-left: 4px solid #2ed573;
}

5. TodoItem.jsの更新

既存のsrc/TodoItem.jsを以下のように更新してください(priorityプロパティを追加)。

import React from 'react';

function TodoItem({ text, completed, priority = "medium" }) {
  return (
    <div className={`todo-item priority-${priority}`}>
      <input 
        type="checkbox" 
        checked={completed} 
        readOnly 
      />
      <span style={{ 
        textDecoration: completed ? 'line-through' : 'none' 
      }}>
        {text}
      </span>
    </div>
  );
}

export default TodoItem;

動作確認

実装が完了したら、開発サーバーが起動している状態でブラウザを確認してください。以下のような表示が確認できます。

TODOアプリ(第2回:完成イメージ)
TODOアプリ(第2回:完成イメージ)
  • タイトルと統計情報(総数、完了数、未完了数)
  • 優先度に応じた色分けされたTODOアイテム(左端の色付きボーダー)

FAQ

コンポーネントが表示されない場合

以下の点を確認してください。

  1. ファイル名とimport文が一致しているか
  2. export defaultが正しく記述されているか
  3. ファイルパスが正しいか
  4. コンポーネント名が大文字で始まっているか
Propsが正しく渡されていない場合

以下の点を確認してください。

  1. 親コンポーネントでpropsを正しく渡しているか
  2. 子コンポーネントでpropsを正しく受け取っているか
  3. プロパティ名が一致しているか
JSXでエラーが発生する場合

以下の点を確認してください。

  1. すべての要素が一つの要素で囲まれているか
  2. 閉じタグが正しく記述されているか
  3. className属性を使用しているか(classではない)
条件付きレンダリングが動作しない場合

以下の点を確認してください。

  1. 条件式が正しく記述されているか
  2. 三項演算子の構文が正しいか
  3. 条件に応じた要素が正しく返されているか
スタイルが適用されない場合

以下の点を確認してください。

  1. CSSファイルが正しくimportされているか
  2. クラス名が正しく記述されているか
  3. CSSの優先度(詳細度)が適切か
コンポーネントの分割で迷った場合

以下の原則を参考にしてください。

  1. 単一責任の原則:一つのコンポーネントに一つの役割
  2. 再利用性:他の場所でも使えるか
  3. 保守性:変更しやすい構造か

まとめ

今回は、ReactのコンポーネントとJSXについて詳しく学習しました。

コンポーネントベース開発により、UIを小さな部品に分割して開発することで、コードの再利用性と保守性を大幅に向上させることができます。

JSXの詳細な文法とPropsの受け渡し方法を理解することで、より柔軟で拡張性の高いコンポーネントを作成できるようになりました。

ケケンタ

次回は、Reactでの状態管理について学習していきます。useStateフックを使って、動的なTODOアプリケーションを作成していきましょう!

この記事が少しでもお役に立ったなら何よりです。次回もお楽しみに!


僕が実際にReact学習に使用した書籍です

【React】コンポーネントとJSXの理解|TODOアプリ【基本編:第2回】のアイキャッチ画像

この記事が気に入ったら
フォローしてね!

この記事が良いと思ったらシェアしてね!

コメント

コメントする

CAPTCHA


目次