0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【コア概念5つ】React完全ガイド|挫折しない学習ロードマップ

Last updated at Posted at 2025-11-03

※この記事は以下記事を参照し、自己学習用として書きました。参照記事が素晴らしいので、ぜひご覧ください。

参照記事
https://read-engineer.com/2020/12/11/react/#index_id2

目次

  1. なぜReactは挫折率が高いのか
  2. Reactを学ぶ前の準備
  3. Reactの5つのコア概念を理解する
    • SPAとコンポーネント設計
    • JSXの書き方
    • 仮想DOMの仕組み
    • StateとPropsによる状態管理
    • React Hooksの基礎
  4. 実践!TodoアプリをReactで作り直す
  5. 次のステップへ
  6. まとめ

1. なぜReactは挫折率が高いのか

ReactはJavaScriptフレームワークの中で圧倒的なシェアを誇りますが、同時に挫折率も非常に高いフレームワークです。その理由は明確です。

JavaScriptの基礎が不十分なまま学習を始めてしまうからです。

Reactは「データを元にUIを自動更新する」技術ですが、その土台となるJavaScript(配列操作、非同期処理、モジュールなど)を理解していないと、何をしているのか全く分からなくなります。

逆に言えば、JavaScriptの基礎さえ固めてからReactに取り組めば、驚くほどスムーズに習得できます。段階を飛ばさず、確実に積み上げていきましょう。


2. Reactを学ぶ前の準備

Reactを始める前に、以下の3つを確認してください。

2-1. JavaScriptの基礎は身についていますか?

特に重要なのがこれらの知識です:

  • 配列操作(map, filter, find)
  • 非同期処理(Promise, async/await)
  • ECMAScriptモジュール(import/export)
  • アロー関数とthisの扱い
  • オブジェクトの分割代入

これらが曖昧な場合は、まずJavaScriptの復習から始めましょう。

2-2. JavaScriptでTodoアプリを作れますか?

これが最も重要です。 素のJavaScriptでCRUD処理(作成・読込・更新・削除)を実装できる力があれば、Reactの学習はスムーズに進みます。

なぜなら、Reactは内部で自動的にデータ操作とUI更新を行いますが、その仕組みを理解するには「手動でやった経験」が必要だからです。

JavaScriptのみでTodoアプリを作ったことがない方は、まずそこから始めましょう。

2-3. ファンクションコンポーネントで学ぶ

Reactには2つの書き方があります:

  • クラスコンポーネント(古い書き方)
  • ファンクションコンポーネント(現在の主流)

2020年以降、React Hooksの登場でファンクションコンポーネントが主流になりました。クラスコンポーネントは複雑でthisの理解も必要なため、まずはファンクションコンポーネントから学びましょう。


3. Reactの5つのコア概念を理解する

3-1. SPAとコンポーネント設計

**SPA(シングルページアプリケーション)**とは、ページ全体を再読み込みせずに画面を切り替える技術です。ReactはSPA構築に最適なフレームワークです。

仕組みはシンプル:HTMLのbodyタグ以下の部分を入れ替えることで、画面遷移しているように見せているだけです。

通常のWebサイト:
ページA → サーバー通信 → ページB(全体を再読み込み)

SPA:
ページA → 表示部分だけ入れ替え → ページB(瞬時に切り替わる)

この入れ替えを実現するのがコンポーネントです。

コンポーネントとは、画面を構成する部品のことです。ボタン、ヘッダー、カード、フォームなど、パーツ単位で作成し、それらを組み合わせて画面を構築します。

画面全体
├── ヘッダー(コンポーネント)
├── メインコンテンツ(コンポーネント)
│   ├── サイドバー(コンポーネント)
│   └── 記事一覧(コンポーネント)
│       ├── 記事カード(コンポーネント)
│       ├── 記事カード(コンポーネント)
│       └── 記事カード(コンポーネント)
└── フッター(コンポーネント)

コンポーネントは入れ子にして使えます。導入される側を親コンポーネント、導入する側を子コンポーネントと呼びます。

3-2. JSXの書き方

ReactではJavaScriptの中にHTMLを書けます。この記法をJSXと呼びます。

// 通常のJavaScript
const element = document.createElement('h1');
element.textContent = 'Hello World';

// JSXを使ったReact
const element = <h1>Hello World</h1>;

JSXの基本ルール:

// シンプルなコンポーネント
function Greeting() {
  const name = "太郎";
  
  return (
    <div>
      <h1>こんにちは、{name}さん!</h1>
      <p>今日もコーディング頑張りましょう</p>
    </div>
  );
}

// {}内にJavaScriptの式を埋め込める
function UserCard() {
  const user = {
    name: "花子",
    age: 20,
    isStudent: true
  };
  
  return (
    <div>
      <h2>{user.name}</h2>
      <p>年齢: {user.age}</p>
      <p>{user.isStudent ? "学生" : "社会人"}</p>
    </div>
  );
}

// classではなくclassNameを使う
function Button() {
  return <button className="btn-primary">クリック</button>;
}

// 必ず1つの親要素で囲む
function Profile() {
  return (
    <div>
      <h1>プロフィール</h1>
      <p>詳細情報</p>
    </div>
  );
}

// または空のタグ(Fragment)を使う
function Profile2() {
  return (
    <>
      <h1>プロフィール</h1>
      <p>詳細情報</p>
    </>
  );
}

3-3. 仮想DOMの仕組み

Reactの最大の特徴が**仮想DOM(Virtual DOM)**です。これにより「変更箇所だけを効率的に更新する」ことが可能になります。

通常のWeb開発の問題点

  • データが変わるたびに画面全体を再描画
  • パフォーマンスが悪い
  • コードが複雑になりがち

Reactの解決策

  1. メモリ上に仮想的なDOM(画面の設計図)を保持
  2. データが変わったら、新しい仮想DOMを作成
  3. 変更前と変更後の仮想DOMを比較
  4. 差分だけを実際のDOMに反映
[変更前の仮想DOM] vs [変更後の仮想DOM]
        ↓
    差分を検知
        ↓
変更箇所だけ実際のDOMを更新(超高速!)

開発者は「データをどう変更するか」だけ考えればよく、画面更新の面倒な処理はReactが自動でやってくれます。

3-4. StateとPropsによる状態管理

Reactでは「データ(状態)が変わったら、自動的にUIが更新される」という仕組みで動きます。この状態を管理する2つの重要な概念があります。

State(ステート):コンポーネント内部の状態

コンポーネントが持つデータのことです。useStateで定義します。

import { useState } from 'react';

function Counter() {
  // [現在の値, 値を変更する関数] = useState(初期値)
  const [count, setCount] = useState(0);
  
  const increment = () => {
    setCount(count + 1);  // 状態を更新するとUIが自動で再描画される
  };
  
  return (
    <div>
      <p>カウント: {count}</p>
      <button onClick={increment}>+1</button>
    </div>
  );
}

重要なポイント:

  • 状態は直接変更してはダメcount = count + 1はNG
  • 必ずsetCount()を使う:これでReactが変更を検知してUIを更新

Props(プロップス):親から子へのデータ受け渡し

親コンポーネントから子コンポーネントへデータを渡す仕組みです。

// 親コンポーネント
function App() {
  const userName = "太郎";
  const userAge = 20;
  
  return (
    <div>
      <UserProfile name={userName} age={userAge} />
    </div>
  );
}

// 子コンポーネント
function UserProfile(props) {
  return (
    <div>
      <h2>{props.name}</h2>
      <p>年齢: {props.age}</p>
    </div>
  );
}

// 分割代入でスッキリ書ける
function UserProfile({ name, age }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>年齢: {age}</p>
    </div>
  );
}

StateとPropsの違い:

State Props
定義場所 コンポーネント内部 親から受け取る
変更 できる できない(読み取り専用)
用途 そのコンポーネントで管理するデータ 親から子への情報伝達

3-5. React Hooksの基礎

React Hooksは、ファンクションコンポーネントで状態管理やその他の機能を使うための仕組みです。代表的なHooksを3つ紹介します。

useState:状態管理

先ほど説明した通り、コンポーネント内の状態を管理します。

function TodoInput() {
  const [text, setText] = useState("");
  
  return (
    <input 
      value={text} 
      onChange={(e) => setText(e.target.value)}
    />
  );
}

useEffect:副作用の処理

データ取得、タイマー、イベントリスナーの登録など、「レンダリング以外の処理」を行います。

import { useState, useEffect } from 'react';

function UserList() {
  const [users, setUsers] = useState([]);
  
  // コンポーネント表示時に実行される
  useEffect(() => {
    const fetchUsers = async () => {
      const response = await fetch('https://api.example.com/users');
      const data = await response.json();
      setUsers(data);
    };
    
    fetchUsers();
  }, []); // 空配列 = 初回のみ実行
  
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

依存配列の動き:

useEffect(() => { ... }, []);        // 初回のみ実行
useEffect(() => { ... }, [count]);   // countが変わったら実行
useEffect(() => { ... });            // 毎回実行(非推奨)

useContext:コンポーネント間の状態共有

Propsでデータをバケツリレーするのではなく、離れたコンポーネント間で直接データを共有できます。

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

// コンテキストを作成
const UserContext = createContext();

// 親コンポーネント
function App() {
  const [user, setUser] = useState({ name: "太郎", role: "admin" });
  
  return (
    <UserContext.Provider value={user}>
      <Header />
      <MainContent />
    </UserContext.Provider>
  );
}

// 深い階層の子コンポーネント
function UserDisplay() {
  const user = useContext(UserContext);
  
  return <p>ようこそ、{user.name}さん({user.role}</p>;
}

4. 実践!TodoアプリをReactで作り直す

JavaScript基礎編で作ったTodoアプリを、Reactで作り直してみましょう。これでReactの状態管理が体感的に理解できます。

完成イメージ

  • タスクを追加・削除できる
  • タスクの完了/未完了を切り替えられる
  • 統計情報を表示する

コード全体

import { useState } from 'react';
import './App.css';

function App() {
  const [todos, setTodos] = useState([]);
  const [inputText, setInputText] = useState("");
  const [nextId, setNextId] = useState(1);

  // タスク追加
  const addTodo = () => {
    if (inputText.trim() === "") return;
    
    const newTodo = {
      id: nextId,
      text: inputText,
      completed: false
    };
    
    setTodos([...todos, newTodo]);
    setNextId(nextId + 1);
    setInputText("");
  };

  // Enter キーで追加
  const handleKeyPress = (e) => {
    if (e.key === 'Enter') addTodo();
  };

  // 完了状態の切り替え
  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  };

  // タスク削除
  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  // 統計計算
  const totalCount = todos.length;
  const completedCount = todos.filter(todo => todo.completed).length;
  const remainingCount = totalCount - completedCount;

  return (
    <div className="container">
      <h1>📝 Todo リスト(React版)</h1>
      
      <div className="input-area">
        <input
          type="text"
          value={inputText}
          onChange={(e) => setInputText(e.target.value)}
          onKeyPress={handleKeyPress}
          placeholder="新しいタスクを入力..."
        />
        <button onClick={addTodo}>追加</button>
      </div>

      <ul className="todo-list">
        {todos.map(todo => (
          <TodoItem
            key={todo.id}
            todo={todo}
            onToggle={toggleTodo}
            onDelete={deleteTodo}
          />
        ))}
      </ul>

      <div className="stats">{totalCount}件 / 完了{completedCount}件 / 残り{remainingCount}</div>
    </div>
  );
}

// 子コンポーネント:個別のTodoアイテム
function TodoItem({ todo, onToggle, onDelete }) {
  return (
    <li className={todo.completed ? 'completed' : ''}>
      <input
        type="checkbox"
        checked={todo.completed}
        onChange={() => onToggle(todo.id)}
      />
      <span>{todo.text}</span>
      <button onClick={() => onDelete(todo.id)}>削除</button>
    </li>
  );
}

export default App;

CSS(App.css)

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  font-family: 'Segoe UI', sans-serif;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  min-height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 20px;
}

.container {
  background: white;
  border-radius: 15px;
  padding: 30px;
  width: 100%;
  max-width: 500px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.3);
}

h1 {
  color: #667eea;
  margin-bottom: 20px;
  text-align: center;
}

.input-area {
  display: flex;
  gap: 10px;
  margin-bottom: 20px;
}

.input-area input {
  flex: 1;
  padding: 12px;
  border: 2px solid #e0e0e0;
  border-radius: 8px;
  font-size: 16px;
}

.input-area input:focus {
  outline: none;
  border-color: #667eea;
}

.input-area button {
  padding: 12px 24px;
  background: #667eea;
  color: white;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  font-size: 16px;
  font-weight: bold;
}

.input-area button:hover {
  background: #5568d3;
}

.todo-list {
  list-style: none;
  margin-bottom: 20px;
}

.todo-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px;
  background: #f8f9fa;
  border-radius: 8px;
  margin-bottom: 10px;
  transition: all 0.3s;
}

.todo-list li:hover {
  background: #e9ecef;
}

.todo-list li.completed span {
  text-decoration: line-through;
  color: #999;
}

.todo-list input[type="checkbox"] {
  width: 20px;
  height: 20px;
  cursor: pointer;
}

.todo-list span {
  flex: 1;
  font-size: 16px;
}

.todo-list button {
  padding: 6px 12px;
  background: #dc3545;
  color: white;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  font-size: 14px;
}

.todo-list button:hover {
  background: #c82333;
}

.stats {
  text-align: center;
  color: #666;
  font-size: 14px;
  padding: 10px;
  background: #f8f9fa;
  border-radius: 8px;
}

JavaScript版との違いを理解する

JavaScript版

  • DOMを直接操作(createElement, appendChild など)
  • データが変わったら手動でHTMLを再構築
  • イベントリスナーを手動で登録

React版

  • JSXで宣言的にUIを記述
  • 状態(State)が変わったら自動でUIが更新される
  • データの流れが分かりやすい

例えば削除機能を比較すると:

// JavaScript版
deleteTodo(id) {
  this.todos = this.todos.filter(t => t.id !== id);
  this.render();  // 手動で画面を再描画
}

// React版
const deleteTodo = (id) => {
  setTodos(todos.filter(todo => todo.id !== id));
  // 自動で再描画される!
};

重要ポイント3つ

  1. 配列の操作にはmap/filterを使う:Reactでは配列を直接変更せず、新しい配列を作って状態を更新します。

  2. keyプロップは必須:リスト表示時は必ずkeyを指定します。Reactが効率的に差分を検知するために必要です。

  3. イベントハンドラーで関数を渡すonClick={() => deleteTodo(todo.id)}のように、アロー関数で引数を渡します。

さらにレベルアップ:Context APIを使う

TodoアプリをContext APIでリファクタリングすると、Propsのバケツリレーを避けられます。

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

// コンテキスト作成
const TodoContext = createContext();

// カスタムフック
const useTodos = () => {
  const context = useContext(TodoContext);
  if (!context) {
    throw new Error('useTodos must be used within TodoProvider');
  }
  return context;
};

// プロバイダーコンポーネント
function TodoProvider({ children }) {
  const [todos, setTodos] = useState([]);
  const [nextId, setNextId] = useState(1);

  const addTodo = (text) => {
    const newTodo = { id: nextId, text, completed: false };
    setTodos([...todos, newTodo]);
    setNextId(nextId + 1);
  };

  const toggleTodo = (id) => {
    setTodos(todos.map(todo =>
      todo.id === id ? { ...todo, completed: !todo.completed } : todo
    ));
  };

  const deleteTodo = (id) => {
    setTodos(todos.filter(todo => todo.id !== id));
  };

  const value = {
    todos,
    addTodo,
    toggleTodo,
    deleteTodo
  };

  return (
    <TodoContext.Provider value={value}>
      {children}
    </TodoContext.Provider>
  );
}

// 使用例
function App() {
  return (
    <TodoProvider>
      <TodoApp />
    </TodoProvider>
  );
}

function TodoApp() {
  const { todos, addTodo, toggleTodo, deleteTodo } = useTodos();
  
  // あとは同じように使える
  // Propsを何階層も渡す必要がない!
}

5. 次のステップへ

Reactの基礎を押さえたら、次は実務で必要なスキルを身につけましょう。

5-1. TypeScriptを学ぶ

モダンなフロント開発では、JavaScriptではなくTypeScriptを使うのが主流です。型定義によってバグを事前に防げるため、ほぼ必須のスキルです。

// TypeScriptでのReact
interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

interface TodoItemProps {
  todo: Todo;
  onToggle: (id: number) => void;
  onDelete: (id: number) => void;
}

function TodoItem({ todo, onToggle, onDelete }: TodoItemProps) {
  // 型が保証されているので安全!
}

5-2. React Routerでルーティング

複数ページを持つSPAを作るには、React Routerが必要です。

import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

function App() {
  return (
    <BrowserRouter>
      <nav>
        <Link to="/">ホーム</Link>
        <Link to="/about">About</Link>
      </nav>
      
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
      </Routes>
    </BrowserRouter>
  );
}

5-3. グローバル状態管理(Redux)

複数のコンポーネントで共通の状態を使いたい場合、ReduxやZustandなどのライブラリを使います。

Context APIでも実現できますが、大規模アプリではReduxの方が管理しやすいケースが多いです。

5-4. 実務レベルのアウトプット

簡単なTodoアプリができたら、次はこれらに挑戦しましょう:

  • APIを使ったデータ取得:外部APIから天気情報やニュースを表示
  • 認証機能付きアプリ:ログイン/ログアウト機能の実装
  • リアルタイム通信:チャットアプリやコラボレーションツール
  • レスポンシブデザイン:スマホ・タブレット対応

6. まとめ

Reactは一見難しそうですが、正しい順序で学べば必ず習得できます。重要なのは段階を飛ばさないことです。

今日から始める3ステップ

  1. JavaScript基礎の確認:配列操作、非同期処理、モジュールを復習。JavaScriptでTodoアプリを作る。

  2. Reactの核心を理解:コンポーネント、JSX、State/Props、React Hooksの概念を掴む。完璧でなくてOK。

  3. 実践!作って学ぶ:TodoアプリをReactで作り直す。動いた瞬間の達成感が次のモチベーションになる。

挫折しないための心構え

  • 最初から全てを理解しようとしない
  • エラーは成長のチャンス
  • 小さく作って、少しずつ機能を追加
  • 分からないことは調べながら進める

ReactはWeb開発の世界で最も求められているスキルの1つです。この記事で紹介した内容を実践すれば、確実にReactエンジニアへの道が開けます。

まずはJavaScriptでTodoアプリを作り、それをReactで作り直してみましょう。その経験が、あなたのキャリアを大きく変える第一歩になるはずです。頑張ってください!

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?