初めてのReact「入門編」導入から基本まで〜TODOアプリを作ってを学ぼう!

JavaScript 最終更新日:2023/12/19 公開日:2019/03/28

react入門

目次

React って何?

React とは UI を作ることに特化した JavaScript のフレームワークです。以下のようなリッチな表現の時間選択のための UI も React を使って実装されていて、 react-gradient-timepicker というライブラリ名で一般に公開されています。

react-gradient-timepicker

そのほかにも、日付選択のためのカレンダー形式の UI や Slick のようなカルーセルの UI も公開されています。React はこういった複雑な UI を作ることが得意なフレームワークです。

ただし、React を使うと、こういった UI が簡単に作れるようになるというわけではなく、JavaScript やプログラムのある程度の知識は必要になってきます。

HTML と JavaScript が合体した JSX 記法

React の特徴として JavaScript 内に HTML の様な独自の記法(JSX)を記述する点が挙げられます。

以下が JSX のサンプルの記述になります。

// RenderListコンポーネントの作成
const RenderList = (props) => {
  return (<ul className="shiritori">
    {props.items.map((item) => <li>{item}</li>)}
  </ul>);
}

// RenderListコンポーネントの利用
const items = ['コアラ', 'ラッパ', 'パリ', 'りんご'];
<RenderList items={items} />

上記の RenderList コンポーネントは単純に配列の値をリスト表示する簡単なコンポーネントです。<ul> など HTML よく見かける記述がありますが、その中に変数や関数の計算結果を出力するために {} を記述します。

この様に HTML と JavaScript が渾然一体となっているのが React の特徴の一つです。

JavaScript と HTML の距離が近いことによって JSON などのデータを HTML に反映させたりすることがとても容易です。JSX の記法を避け、普通の JavaScript で React を使うこともできます。

その場合以下の様な記述になります。

const e = React.createElement;

ReactDOM.render(
  e("ul", { className: 'shiritori' }, 
    e("li", null, 'コアラ'), 
    e("li", null, 'ラッパ'), 
    e("li", null, 'パリ'), 
    e("li", null, 'リンゴ'), 
  )
);

記述量が少なければ普通の JavaScript で記述してもわかるのですが記述量が多くなってくると HTML を JavaScript で表現するのは難しくなってきます。そのため HTML の様に直感的に記述できる JSX 記法が提供されています。

HTML が自動で更新されるリアクティブなプログラミング

React のいいところはデータを更新しただけで自動で HTML が更新される仕組みにあります。例えば以下の codepen は、入力された二つの input から合計値を計算する簡単なコンポーネントの例です。

input に値を入力するとその合計値がリアルタイムに反映されているのがわかるかと思います。

See the Pen
React サンプルコード
by webkikaku (@webkikaku)
on CodePen.

必要な部分だけが更新される仮想 DOM

React の大きな特徴として、仮想 DOM という仕組みをライブラリ本体に持っている点です。

仮想 DOM は実際の DOM ではなく、React が内部的に持っている DOM の情報になります。その仮想 DOM と実際の HTML 上の DOM を比較しその差分だけが毎回 HTML 上に再適用されます。そのため画面全体が React で構成されていたとしても、必要な部分しか更新されないため非常に高速に動作します。

jQuery との違い

jQuery と React の最大の違いは HTML を自分で更新する必要があるかどうかという点です。

変数の値に応じて宣言的に JSX を記述するため、データを更新すると自動で宣言した通り、HTML が更新されます。

jQuery の addClass や ppend 、attr などほとんどのメソッドを使う機会が無くなります。jQuery の場合、データの更新作業と HTML の書き換え作業を同時に行う必要があり読み難いコードになりがちです。

Reactの書き方

React は他のライブラリと比較すると覚えることが少ないです。とてもシンプルな設計になっていてライフサイクル、JSX、state、props について理解できればスラスラコードを書ける様になるでしょう。

JSXを理解しよう

まずは一番の鬼門である JSX を理解しましょう。JSX は HTML をタグの様に記述できるのですが、HTML との違いがいくつかあるのでその違いを押さえましょう。

class ではなく、className

React では、JavaScript の文法の一つである class と区別するために HTML タグの class を className と表現します。また label タグなどに使う for 属性も JavaScript の for 文と区別するために htmlFor を代わりに使います。

<div className="sample"></div>

HTML タグに変数や数字、boolean を代入するときは {} で括る

React では、文字列以外の値(数字、boolean、変数など)を HTML タグの属性に代入する際には {} を使います。

const str = 'sample';
<div className={str} contentEditable={false}></div>

リストの表示方法

ul や ol などのリストの中にアイテムをループして表示させたい際に React ではよく以下の様な表現が用いられます。

const siritori = ['コアラ', 'ラッパ', 'パリ' 'リンゴ'];

<ul className="shiritori">
  {shiritori.map(item => <li>{item}</li>)}
</ul>

配列(Array)のメソッドである map が用いられていますが、このメソッドでは、siritori という配列を以下の様に li タグ付きの配列に変換しています。

[
  <li>{'コアラ'}<li>, 
  <li>{'ラッパ'}</li>, 
  <li>{'パンダ'}</li>, 
  <li>{'ダチョウ'}</li>, 
  <li>{'ウリ'}</li>
];

props と state を理解しよう

次に React の props と state を理解しましょう。まずは props からです。

props は外部から注入される変数です。以下のコードでは RenderList コンポーネントに文字列配列を items として渡しています。渡された items は RenderList コンポーネントが class の場合は this.props.items という形で取得することができます。

class RenderList extends React.Component {
  render() {
    const items = this.props.items;
    return (<ul className="shiritori">
      {items.map(item => <li>{item}</li>)}
    </ul>);
  }
}

ReactDOM.render(<RenderList items={['コアラ', 'ラッパ', 'パリ', 'リンゴ']} />,
document.querySelector('#app'));

RenderList コンポーネントの出力結果

<ul className="shiritori">
  <li>コアラ</li>
  <li>ラッパ</li>
  <li>パリ</li>
  <li>リンゴ</li>
</ul>

また React ではコンポーネントを関数として表現することもできます。その場合は外部から注入された値の記述の仕方が異なります。

関数で RenderList コンポーネントを作る場合

const RenderList = (props) => {
  const { items } = props;
  return (<ul className="shiritori">
    {items.map(item => <li>{item}</li>)}
  </ul>);
}

ReactDOM.render(<RenderList items={['コアラ', 'ラッパ', 'パンダ', 'ダチョウ', 'ウリ']} />,
document.querySelector('#app'));

次に state を理解しましょう。

state はそのコンポーネントが内部的に持っている状態のことです。この状態は props と違い外部から注入できません。以下のサンプルコードではラジオボタンを3つ用意して選択された項目が表示されます。

class SelectItem extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      selected: ''
    };
    this.onChange.bind(this);
  }

  onChange(e) {
    this.setState({ selected: e.target.value });
  }
  
  render() {
    const { selected } = this.state;
    return(<div>
      <p>現在 {selected} が選択されています。</p>
      <label>
        <input type="radio" value="コアラ" onChange={this.onChange}/>
        コアラ
      </label>
      <label>
        <input type="radio" value="ラッパ" onChange={this.onChange} />
        ラッパ
      </label>
      <label>
        <input type="radio" value="パリ" onChange={this.onChange} />
        パリ
      </label>
    </div>);
  }
}

ReactDOM.render(<SelectedItem />, document.querySelector('#app'));

ライフサイクルを理解しよう

次は React のライフサイクルを理解しましょう。ライフサイクルとはコンポーネントが生成されてから削除されるまでの間の一連の流れのことを指します。React ではこのライフサイクル間のあるタイミングで処理を挟み込むための一連のメソッドが用意されています。

class Example extends React.Component {
  constructor(props) {
    super(props);
  }

  // コンポーネント生成時
  componentDidMount() {
  }

  // コンポーネント更新時
  componentDidUpdate() {
  }

  //コンポーネント消滅時
  componentWillUnmount() {
  }
}

React のライフサイクルを理解しやすいように以下のような図を作って見ました。

ライフサイクル

コンポーネント生成時

コンポーネントが呼ばれた際には constructor が呼ばれます。これは class の初期化メソッドで、プログラムに精通している人だとご存知だと思います。

次に getDerivedStateFromProps です。これは親コンポーネントから渡された props を計算して自身の state を導き出すためのメソッドです。

内部の state が props の値に依存する場合は getDerivedStateFromProps を使います。その後仮想DOMを更新するための render メソッドが実行され、実際にコンポーネントの DOM が生成された後、componentDidMount が実行されます。

コンポーネント更新時

内部の state が変更された時、もしくは親コンポーネントから新しい props が渡ってきた際にコンポーネントの一連の更新処理がされます。

コンポーネント生成時と同じように getDerivedStateFromProps が実行された後、コンポーネントを再描画する必要があるかどうかを判定するための shouldComponentUpdate メソッドが動きます。

もし再描画したい場合はメソッド内で true を返します。再描画したくない場合は false を返します。false が返されると、そのあとの render メソッド、componentDidUpdate メソッドは動きません。

shouldComponentUpdate メソッドが存在しない場合は render メソッドがそのまま実行されます。もし state や props が更新されてもコンポーネントを再描画したくない場合は shouldComponentUpdate を使ってパフォーマンスチューニングしてください。

render メソッド実行後、DOMが更新されたタイミングで、componentDidUpdate メソッドが実行されます。

コンポーネント消滅時

仮想 DOM からこのコンポーネントが消滅したタイミングで componentWillUnmount メソッドが実行されます。そしてその後実際の DOM からも削除されます。

フック(Hooks)の使用

React 16.8の導入以降、フックはReactアプリケーションの開発において中心的な役割を担うようになりました。フックを使用することで、クラスコンポーネントを書かずに、状態やライフサイクルの機能を関数コンポーネント内で使用できるようになります。

基本的なフック

1. useState
`useState`は、関数コンポーネントにローカル状態を追加することを可能にします。このフックは状態の現在値と、それを更新するための関数をペアとして返します。
例:

     const [count, setCount] = useState(0);
     

2. useEffect
`useEffect`は、コンポーネントのレンダリング後に何かを実行するために使用されます。これは、クラスコンポーネントのライフサイクルメソッド`componentDidMount`、`componentDidUpdate`、`componentWillUnmount`に相当します。
例:

     useEffect(() => {
       // ブラウザのタイトルを更新
       document.title = `You clicked ${count} times`;
     });
     

3. useContext
`useContext`フックは、コンテキストの現在値を関数コンポーネントで読み取ることを可能にします。これにより、プロップスを介さずに、近くのコンテキストプロバイダから値を取得できます。

追加フック

Reactには他にも多くのフックがありますが、`useReducer`、`useCallback`、`useMemo`、`useRef`などがよく使用されます。これらのフックは、より複雑なコンポーネントやパフォーマンスの最適化が必要な場合に有用です。

ルールとベストプラクティス

フックを使用する際には、いくつかのルールとベストプラクティスに従うことが重要です。

  • フックは関数のトップレベルでのみ呼び出す … フックはループ、条件分岐、ネストされた関数内では呼び出さないでください。
  • フックはReact関数コンポーネント内でのみ呼び出す … 通常のJavaScript関数内ではフックを使用しないでください。
  • カスタムフックを作成する … 複数のコンポーネント間で同じロジックを共有する場合、カスタムフックを作成して再利用することを検討してください。

このセクションでは、フックの基本的な使用方法と概念を紹介しましたが、実際にはより多くのフックとそれらを利用するさまざまな方法が存在します。フックはReactの強力な機能の一つであり、関数コンポーネントをより表現力豊かで管理しやすいものに変えています。

パフォーマンス最適化

Reactアプリケーションのパフォーマンス最適化は、ユーザー体験を向上させるために重要な側面です。良いパフォーマンスは、アプリケーションが素早く応答し、効率的に動作します。

コンポーネントの最適化

不要なレンダリングの回避

‘React.memo’、’shouldComponentUpdate’などを使用して、コンポーネントが不要な場合にレンダリングを回避します。

例:

 export default React.memo(function MyComponent(props) {
   // コンポーネントの実装
 });

useStateの関数型アップデート

‘useState’フックの関数型アップデートを利用して、前の状態に基づいたアップデートを行います。

useMemoとuseCallback

計算コストの高い処理は’useMemo’でメモ化し、コールバック関数は’useCallback’でラップして再利用します。

コード分割

ダイナミックインポートとReact.lazy

コード分割を使用して、アプリケーションの初期ロード時間を短縮します。
‘React.lazy’とダイナミックインポートを使用して、必要な時にのみコンポーネントをロードします。

例:

const OtherComponent = React.lazy(() => import('./OtherComponent'));

リソースの最適化

画像の遅延ロード

画像やその他のメディアリソースの遅延ロードを実装して、初期ロード時間を減らします。

不要なライブラリの削減

バンドルサイズを減らすために、不要な依存関係やライブラリを削除します。

開発ツールの利用

React Developer Tools

React Developer Toolsを使用して、パフォーマンスのボトルネックを特定し、最適化の機会を見つけます。

パフォーマンスモニタリング

Web Vitalsやその他のパフォーマンスモニタリングツール

実際のユーザー体験に基づいたパフォーマンス測定を行うために、Web Vitalsや他のパフォーマンスモニタリングツールを活用します。

Reactの導入方法

Node.js のインストール

React の概念が理解できたところで次はいよいよ React を導入してみましょう。React を使うには Node.js というツールを利用するのが便利です。

Node.js とはもともとサーバーサイドで JavaScript を動かすためのツールなのですが、昨今では gulp や Webpack などフロントエンドを便利に開発するためのツールとしても使われるようになりました。

nodejs

上記の URL から Node.js をダウンロードしていただきダウンロードしたパッケージを解凍するだけでインストールが始まります。Node.js の導入は非常に簡単です。

Create React App のインストール

Node.js のインストール後、地道に React 環境を構築するのはとても大変です。Webpack や Babel もしくは TypeScript などの知識に精通している必要があります。

Create React App はそういった難しい設定をしなくても簡単に React を導入できるツールです。より細かい設定をしたい場合は Create React App を使わずに直接 Webpack を設定した方が早い場合もありますが趣味程度に使ってみるくらいなら Create React App でも十分です。

以下3つのコマンドをターミナルに入力するだけで何も考えずに React 環境が完成してしまいます。

npx create-react-app my-app
cd my-app
npm start

以下のような画面が立ち上がれば成功です。

Create React App

my-app ディレクトリーをお好きなテキストエディターで開いていただいて、my-app/src/App.js を変更すると変更結果がブラウザーにすぐ反映されるはずです。

実践編 Todo アプリを作ろう

React の環境が整ったのでいよいよここから実践編です。React で簡単な todo アプリを作って見ましょう。完成形を codepen に投稿してみました。

See the Pen
Reactで作るtodoアプリ
by webkikaku (@webkikaku)
on CodePen.

折角なので codepen 上ではなく先ほど Create React App で作成した環境を利用しましょう。

Todo クラスを作ろう

まずは todo クラスを作っていきます。my-app/src/todo.js を作成してください。以下がコンポーネントの class を作る際の雛形になります。

import React, { Component } from 'react';

class Todo extends Component {

}

render メソッドを定義

次にどのように HTML を描画するかを決めるための render メソッドを作りましょう。ここでは todo 名を入力するためのテキストフィールド、入力した todo をリストに追加するためのボタンと todo 一覧を表示するためのリストを作っています。

import React, { Component } from 'react';

class Todo extends Component {

  constructor(props) {
    super(props);
    this.state = {
      todos: [],
      name: ''
    };
  }

  render() {
    const { todos } = this.state;
    
    return (<div>
      <input type="text" />
      <button>登録</button>
      <ul>
        {todos.map((todo, index) => <li key={index}>{todo}</li>)}
      </ul>
    </div>);
  }
}

todo の追加メソッドを定義

次に todo を実際にリストに追加するためのメソッドを作って見ましょう。まずはテキストフィールドに入力された値を name として state に保存しましょう。React では state を保存するために setState というメソッドを使います。実際に入力された値は e.target.value で取り出せます。

class Todo extends Component {
  ...
  onInput = (e) => {
    this.setState({
      name: e.target.value
    });
  }
  ...
  render() {
    const { todos } = this.state;
    
    return (<div>
      <input type="text" onInput={this.onInput} />
      <button>登録</button>
      <ul>
        {todos.map((todo, index) => <li key={index}>{todo}</li>)}
      </ul>
    </div>);
  }
}

次に登録ボタンをクリックした際の処理を追加します。以下のコードでは、スプレッド演算子を使って配列を新しい配列に展開し、その末尾にテキストフィールドで入力した値をセットしています。

class Todo extends Component {
  ...
  addTodo = () => {
    const { todos, name } = this.state;
    this.setState({
      todos: [...todos, name]
    });
  }
  ...
  render() {
    const { todos } = this.state;
    return (<div>
      <input type="text" onInput={this.onInput} />
      <button onClick={this.addTodo} >登録</button>
      <ul>
        {todos.map((todo, index) => <li key={index}>{todo}</li>)}
      </ul>
    </div>);
  }
}

todo の削除メソッドを定義

次に todo を削除するボタンを作りましょう。removeTodo メソッドで削除したい todo の index 番号を受け取ってその位置にある todo を除いた配列を作り、state の todos に再セットしています。

class Todo extends Component {
  ...
  removeTodo = (index) => {
    const { todos, name } = this.state;
    this.setState({
      todos: [...todos.slice(0, index), ...todos.slice(index + 1)]
    });
  }
  ...
  render() {
    const { todos } = this.state;
    return (<div>
      <input type="text" onInput={this.onInput} />
      <button onClick={this.addTodo} >登録</button>
      <ul>
        {todos.map((todo, index) => <li key={index}>
          {todo}
          <button onClick={() => { this.removeTodo(index) }}>削除</button>
        </li>)}
      </ul>
    </div>);
  }
}

完成形は以下のようなソースコードになります。他のファイルで作った todo を読み込めるように class の先頭に export default を追加しています。

import React, { Component } from 'react';

export default class Todo extends Component {

  constructor(props) {
    super(props);
    this.state = {
      todos: [],
      name: ''
    };
  }

  onInput = (e) => {
    this.setState({
      name: e.target.value
    });
  }
  
  addTodo = () => {
    const { todos, name } = this.state;
    this.setState({
      todos: [...todos, name]
    });
  }

  removeTodo = (index) => {
    const { todos, name } = this.state;
    this.setState({
      todos: [...todos.slice(0, index), ...todos.slice(index + 1)]
    });
  }

  render() {
    const { todos } = this.state;
    return (<div>
      <input type="text" onInput={this.onInput} />
      <button onClick={this.addTodo} >登録</button>
      <ul>
        {todos.map((todo, index) => <li key={index}>
          {todo}
          <button onClick={() => { this.removeTodo(index) }}>削除</button>
        </li>)}
      </ul>
    </div>);
  }
}

最後に my-app/src/index.js で先ほど作成した todo コンポーネントを読み込めば完成です。

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import Todo from './todo';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<Todo />, document.getElementById('root'));
// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

まとめ

これまで React を始める上での基礎をお伝えしました。JSX の記法に慣れて、props, state やライフサイクルを理解すれば React で複雑なコンポーネントも作れます。

ただし React で本格的にアプリを作るのであればその周辺技術も学ぶ必要があります。

例えば複数のコンポーネントを管理するためにアプリケーション全体の state を管理するためのライブラリとして react-redux, redux などがあります。また URL ごとに表示するコンポーネントを出し分けるためのツールとして react-router があり、React をサーバーサイドでレンダリングするためのツールとして Next.js があります。

これらの周辺技術と組み合わせながら Web アプリケーションを作ることがほとんどなので、React でコンポーネントが作れるようになった後はこういった技術も勉強して行きましょう。この記事でまずは React を始める最初の一歩を踏み出していただければ幸いです。

他にも Vue の入門についても公開していますので、興味のある方は下記リンクからどうぞ!

CONTACT

Webサイト制作のご相談やご質問、ご不明点などございましたらこちらよりお問い合わせください。
「ホームページ制作について」とお伝えください。担当者におつなぎいたします。

オフィス一覧へ

受付時間|9:00~18:00(土・日・祝除く)

※お電話にてお問い合わせの際はオフィス一覧からお近くのオフィスにご連絡ください

※全国対応

ホームページ無料診断 毎月10社限定

ホームページ制作のプロがユーザビリティ・SEO・競合などを多角的に分析し、
具体的な改善案をご提案します。

無料診断する