LoginSignup
1
4

More than 3 years have passed since last update.

React入門 学習メモ

Last updated at Posted at 2020-10-09

はじめに

以下の知識の習得を目的として行った学習メモになります。

  • Reactの基礎知識
  • JSXについて
  • create-react-appでの環境構築
  • Reactコンポーネントの作り方
  • モジュールのimport、exportについて
  • React Hooksについて

Reactの基礎知識

Reactとは?

  • Facebookが開発
  • JavaScriptのライブラリ(フレームワークではない)
  • WebのUIを作る
  • React ≠ SPA

コンポーネントとは?

UIは2つに分類される
1. 見た目(View)
2. 機能(Controller)

コンポーネント = 見た目 + 機能

Webページはコンポーネントのツリー構造になっている

なぜコンポーネントを使うのか

  • 再利用性するため
  • 分割統治するため
  • 変更に強くするため

Virtual DOM

そもそもDOMとは?

→ Document Object Modelの略
→ インターフェース
→ HTMLにアクセスする窓口
→ HTML構造、見た目、コンテンツを変更したいときはDOMを通して操作を行う

Virtual DOMとは?

Reactで管理するDOM。
通常のDOMはブラウザのレンダリングによって管理されるが
Reactではブラウザのレンダリングと別で管理を行う
→効率よくDOM操作できる

通常のDOM操作

document.getElementById('hoge').innerText='fuga';

ReactのVirtual DOM操作

render(
  <div id='hoge'>fuga</div>
);

差分描画

Reactでは変更されたVirtual DOMの差分のみを再描画する

JSX

JavaScript内でHTMLっぽく書ける

ReactDOM.render(
  <div className={hoge}>
    <h1>Hello World!</h1>
  </div>
)

JSXの基礎知識と文法

JSXとは?

  • JavaScript内でHTMLを簡単に記述するための言語
  • JavaScriptの拡張言語
  • Facebookが開発
  • React公式ドキュメントはほぼJSXで記述されている
  • Reactでは業界標準

なぜJSXを使う?

通常のJavaScriptでHTMLを記述(DOM操作)

const fuga = "<h1>Hello, World!</h1>"
document.getElementById('hoge').innerHTML = fuga;

量が増えると。。

const fuga = "<h1>Hello, World!</h1>"
const foo = "<h2>React Commentary</h2>"
const bar = "Hi, I'm Billy Gibbons."
document.getElementById('hoge').innerHTML = fuga;
document.getElementById('foo').innerHTML = foo;
document.getElementById('bar').innerHTML = bar;

JSXを使うと。。

return (
  <React.fragment>
    <div id="hoge">
      <h1>Hello, World!</h1>
    </div>
    <div id="foo">
      <h2>React Commentary</h2>
    </div>
    <p id="foo">Hi, I'm Billy Gibbons.</p>
  </React.fragment>
)

可読性が高い!

ただJSXは実際のところJavaScriptではない。
JSXの構文をブラウザは理解できない。

そこでトランスパイラが必要。

トランスパイラ

「翻訳」のような役割。
JSX → JavaScript(ES6) → JavaScript(ES5)

ReactのトランスパイラはBabel

トランスパイラを主たる実装として開発されている言語の例
CoffeeScript、TypeScript...etc

もしJSXがなかったら。。

React.createElementを使う

React.createElement(
  "h1",
  null,
  "Hello, World!"
)

JSXを使用して記述したJSをBabelでトランスパイルするとReact.createElementを使用した形に変換される

JSXの基本文法

1.Reactパッケージのインストールが必要

// .jsxファイル内の先頭に宣言
import React from "react";

2.HTMLとほぼ同じ文法(ただclassclassNameに)

const App = () => {
  return (
    <div id="hoge" className="fuga">
      <h1>Hello, World!</h1>
    </div>
  );
};

3.{}内に変数や関数を埋め込める

const foo = "<h1>Hello, World!</h1>"
const App = () => {
  return (
    <div id="hoge" className="fuga">
      {foo}
    </div>
  );
};

4.変数名などは全てキャメルケースで記述する

const fooBar = "<h1>Hello, World!</h1>"
const App = () => {
  return (
    <div id="hoge" className="fuga">
      {fooBar}
    </div>
  );
};

5.空要素は閉じる

const App = () => {
  return (
    <div id="hoge" className="fuga">
      <input type="text" id="blankElement" />
      <img src="/assets/icon/icon.png" />
    </div>
  );
};

環境構築

create-react-app

必要なもの

  • node 8.10以上
  • npm 5.6以上

上記インストールのためにhomebrew、nodebrewが必要

homebrewのインストール

nodebrewのインストール

$ brew install nodebrew
$ nodebrew -v // インストールの確認

nodeのインストール

参考:https://qiita.com/kyosuke5_20/items/c5f68fc9d89b84c0df09

$ nodebrew ls-remote // インストール可能なnodeのバージョン確認
$ nodebrew install stable // 安定版のインストール
$ nodebrew ls // 現在インストールされているnodeのバージョン一覧
$ nodebrew use v{インストールしたバージョン} // currentへの追加
$ echo 'export PATH=$HOME/.nodebrew/current/bin:$PATH' >> ~/.zprofile // zshの場合

npmのインストール

nodeを入れた時点でnpmも入る
バージョンが5.6以上であることを確認する

npm -v

create-react-appによるプロジェクトの作成

$ npx create-react-app react-blog-app

create-react-appとは

React開発環境を超簡単に構築できるツール。
Reactを学習するのに最適な環境
(React公式documentから引用)

  • React開発環境の構築は難しい
  • トランスパイラのbabelやバンドラーのwebpackの設定が必要

create-react-appなら1コマンドで環境を整えてくれる

create-react-appの環境構成

  1. src : コンポーネントを作るJSファイルなど
  2. public : htmlファイルや設定ファイルなど。manifest.jsonはPWAを開発する際に使用する設定ファイル
  3. build : 本番環境用のファイル

基本コマンド

$ npm run build

srcとpublic内のファイルを1つにまとめて(バンドル)、buildディレクトリに出力する

$ npm start

ローカルサーバを起動してReactアプリを動かす

$ npm run eject

babelやwebpackの設定を変更したい時に使用する

その他の環境構築ツール

  • Next.js → サーバーサイドレンダリング(SSR)
  • Gatsby → 静的ウェブサイトに最適(SSG)

コンポーネントの基本

コンポーネントとは?

UIは2つに分類される
1. 見た目(View)
2. 機能(Controller)

コンポーネント = 見た目 + 機能

Webページはコンポーネントのツリー構造になっている

なぜコンポーネントを使うのか

  • 再利用性するため
  • 分割統治するため
  • 変更に強くするため

コンポーネントの種類

  1. Class Component : クラスによって定義されたコンポーネント
  2. Functional Component : 関数型で定義されたコンポーネント

Functional Component

  • ES6のアロー関数で記述
  • stateを持たない(stateless)
  • propsを引数に受け取る
  • JSXをreturnする
  • シンプル
Article.jsx
import React from 'react';

const Article = (props) => {
    return (
        <div>
            <h2>{props.title}</h2>
        </div>
    );
};

export default Article;

Class Component

  • React.Componentを継承
  • ライフサイクルやstateを持つ
  • propsにはthisが必要
  • renderメソッド内でJSXをreturnする
Article.jsx
import React from 'react';

class Article extends React.Component {
    constructor(props) {
        super(props);
    }
    render() {
        return (
            <div>
              <h2>{this.props.title}</h2>
            </div>
        );
    }
}

export default Article;

最近の主流はFunctional Component

  • 記述量が少ない
  • コンポーネントにstateを持たせたくない

propsでデータを受け渡す

親コンポーネント

Blog.jsx
import React from 'react';
import Article from "./Article";

const Blog = () => {
    return (
        <React.Fragment>
            <Article title={'Hello, React'}/>
        </React.Fragment>
    );
}

export default Blog;

子コンポーネント

Article.jsx
import React from 'react';

const Article = (props) => {
    return (
        <div>
            <h2>{props.title}</h2>
        </div>
    );
};

export default Article;

受け渡せるデータ型

  • {}内に記述
  • 文字列、数値、真偽値、配列、オブジェクトなどなんでも渡せる
  • 文字列は{}なくてもOK
Blog.jsx
import React from 'react';
import Article from "./Article";

const Blog = () => {
    const authorName = 'Eric Clapton';
    return (
        <React.Fragment>
            <Article
                title={'Hello, React.'}
                order={3}
                isPublished={true}
                author={authorName}
            />
        </React.Fragment>
    );
}

export default Blog;

再利用する

コンポーネントは再利用できることが最大の利点

Blog.jsx
import React from 'react';
import Article from "./Article";

const Blog = () => {
    const authorName = 'Eric Clapton';
    return (
        <React.Fragment>
            <Article title={'出生について'}/>
            <Article title={'Cream時代'}/>
            <Article title={'ソロ活動時代'}/>
        </React.Fragment>
    );
}

export default Blog;

コンポーネントの状態

stateの設定と取得と変更

状態(state)とは

  • コンポーネントの中で管理する変数
  • ローカルステートと呼ばれる
  • propsとして子コンポーネントに渡せる

なぜstateを使うのか

  • render()内では値を変更してはいけない
  • setState()で値を変更する
  • stateの変更 = 再レンダーのきっかけ
    →ページをリロードせずに表示を切り替えられる

stateの設定方法

  • Class Componentが前提
  • constructor()内で宣言
  • オブジェクト型で記述
Blog.jsx
import React from 'react';
import Article from "./Article";

class Blog extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            isPublished: false
        }
    }
    // 略
}

export default Blog;

stateの取得

  • 同コンポーネント内ならthis.state.key名で取得できる
  • 子コンポーネントで参照したい場合はpropsとして渡す
Blog.jsx
render() {
  return (
    <React.Fragment>
      <Article
        title={'出生について'}
        isPublished={this.state.isPublished}
      />
    </React.Fragment>
  );
}

stateの変更方法

  • setState()を使う
  • 関数にラップするのが一般的
  • setState()内に記述されたstateのみを変更
Blog.jsx
    // 公開状態を反転させる関数を定義する
    togglePublished = () => {
        this.setState({
           isPublished: !this.state.isPublished
        });
    }

コンポーネントのライフサイクル

ライフサイクルとは

  • コンポーネントの「時間の流れ」
  • 生成、変更、破棄までの循環
  • それぞれの段階で必要な処理を記述

3種類のライフサイクル

Mounting:コンポーネントが生成される期間
Updating:コンポーネントが変更される期間
Unmounting:コンポーネントが破棄される期間

なぜライフサイクルを使うのか

  • 関数外に影響を与える関数を記述するため
    e.g. DOM変更、API通信、ログ出力、setState() ...etc
  • 副作用 = 適切な場所に配置すべき処理
order Mounting Updating Unmounting
1 constructor()
2 render() render()
3 componentDidMount()
4 componentDidUpdate()
5 componentWillUnmount()

主要メソッド

Mount

constructor():初期化(stateなど)
render():VDOMを描画(JSXをreturn)
componentDidMount():render()後に一度だけ呼ばれる。リスナーの設定やAPI通信に使われる。

Updating

render():VDOMを描画(JSXをreturn)
componentDidUpdate():再render()後に呼ばれる。スクロールイベントや条件付きイベント。

Unmounting

componentWillUnmount():コンポーネントが破棄される直前に呼ばれる。リソースを解放するために使う。(リスナーの解除など)

importとexport

モジュール化について

  • 他言語では昔からある概念
  • JavaScriptではES2015(ES6)から採用
  • 基本的に1ファイル=1モジュール
  • 任意の場所で読み込んで使用できる

モジュール化のメリット

  1. 分割統治できる
    大規模プログラムでも管理しやすくなる
  2. 任意の場所で読み込める
    必要なものを必要な分だけ
  3. 再利用できる
    何度も同じコードを書かなくていい

名前付きexport

1モジュールから複数の関数をexport
クラスはexportできない

index.js
export function Foo() {
  return (
    <h1>FOO</h1>
  );
}
export const Bar = () => {
  return (
    <h1>BAR</h1>
  );
}

名前なし(default)export

  • 1ファイル(1モジュール) 1export
  • ES6で推奨されているexport方法
  • アロー関数は宣言後にexport
  • クラスをexportできる
Foo.js
export default function Foo() {
  return (
    <h1>FOO</h1>
  );
}
Bar.js
const Bar = () => {
  return (
    <h1>BAR</h1>
  );
}
export default Bar;
Hoge.js
export default class Hoge extends Fuga {
  render() {
    return (
      <h1>Hoge</h1>
    );
  }
}

モジュール全体のimport

  • 名前なし(default)exportしたモジュールをimportする
  • モジュール全体のimport
Blog.jsx
import React from 'react';
import Article from "./Article";
Article.jsx
const Article = (props) => {
  return (
    <div>Article</div>
  );
}
export default Article;

関数ごとのimport

  • 名前付きexportされたモジュールをimportする
  • {}内にimportしたい関数名
Hoge.js
import { Foo, Bar } from "./FooBar";
FooBar.js
export function Foo() {
  return (
    <h1>FOO</h1>
  );
}
export const Bar = () => {
  return (
    <h1>BAR</h1>
  );
}

別名import

  • 別名(エイリアス)をつけてimportできる
  • モジュール全体なら * as name
  • モジュール一部なら A as B
Blog.jsx
import React from 'react';
import * as AnotherName from './Article';
import { Foo as MyFoo } from './FooBar';
Article.js
const Article = (props) => {
  return (
    <div>Article</div>
  );
}
export default Article;

React Hooks

関数コンポーネントでもstateを扱う

Hookとは

  • クラスの機能(stateやライフサイクル)をFunctional Componentでも使える機能
  • React 16.8から導入された(2020/2に正式リリース)
  • 100%後方互換
    →古い書き方をしているコンポーネントなどに影響を及ぼさない
    →小さく導入できる

なぜHookを使うのか

シンプルさを保つため

  • Class Componentは複雑になりやすい
    • thisという悪魔
    • stateを扱うロジックが複雑
    • 複数のライフサイクルメソッドに副作用のある処理がまたがる

useState()を使う

  • ステートフックと呼ばれる
  • クラスコンポーネントでいうthis.statethis.setState()の代替
  • 複数のstateを扱うときはstate毎に宣言する

1.useState関数をインポート

import React, {useState} from 'react';

2.宣言する

const [isPublished, togglePublished] = useState(false);

3.JSX内で使う

<input // onClick={() => togglePublished(!isPublished)} />

Functional Componentでもライフサイクルを扱う

useEffect()を利用する

useEffect()のメリット

  • ライフサイクルメソッドを代替できる
  • Functional Componentでライフサイクルを扱える
  • コードをまとめることができる
    • 🙆‍♀️ 機能ベース(何をやっているのか)
    • 🙅‍♀️ 時の流れベース(ライフサイクルのメソッド毎)

useEffect()の仕組み

  • レンダー毎にuseEffect()内の処理が走る
  • 代替できるメソッド
    • componentDidMount()
    • componentDidUpdate()
    • componentWillUnmount()

useEffect()の使用

パターン① レンダー毎

useEffect(() => {
  console.log('Render!');
  return () => {
    console.log('Unmounting!');
  }
})
  • 基本形
  • useEffect()内にCallback関数を書く
  • Callbackはレンダー毎に呼ばれる
  • returnするCallback関数はアンマウント時に呼ばれる。(クリーンアップ関数)

パターン② マウント時のみ実行

useEffect(() => {
  console.log('Render!');
}, [])
  • 第二引数の配列内の値を前回レンダーと今回レンダーで比較
    • 変更があればCallback関数を実行
  • 第二引数に空の配列を渡すと最初の1回(マウント時)のみ実行される

パターン③ マウント&アンマウント時に実行

useEffect(() => {
  console.log('Render!');
  return () => {
    console.log('Unmounting!');
  }
}, [])
  • ①と②の複合形
  • 通常のCallbackはマウント時のみ
    • 配列が空の場合はUpdating期間は処理が実行されない
  • アンマウント時はretrun内のクリーンアップ関数が実行される

パターン④ 特定のレンダー時に実行

const [limit, release] = useState(true);

useEffect(() => {
  console.log('Render!');
}, [limit])
  • マウント時に実行される
  • limitの値が変わった時に実行される
1
4
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
1
4