はじめに
初学者の私がReactについて学んだことをアウトプットする記事です。
主な目的は自分がこの記事を開けばReactについて復習できるようにする備忘録です。
目次
- Reactとは
- JSXの基礎知識と文法
- create-react-app
- コンポーネントの基本データの受け渡しと再利用
- コンポーネントの状態stateの設定と取得と変更
- コンポーネントのライフサイクル 副作用の有る処理を書こう
- importとexport モジュールを使いこなそう
- React-Hooks 関数コンポーネントでもステートを使おう
- React-Hooks 関数コンポーネントでもライフサイクルを使おう
Reactとは
概要
Facebook社が開発したライブラリで、WebのUIを作るもので、決してSPAを作るものではない。
チャットボットだけReact、ボタン機能だけReactで実装することも出来る。
コンポーネントとは
UIは2つに分類される。
1. 見た目(View)
2. 機能(Controller)
コンポーネント=見た目+機能
コンポーネントのツリー構造
HTMLの下にヘッダーやメイン、その下にnav,login-button,content,linkなどが存在する。
DOM
DOM=Document Object Model=インターフェイス
HTMLにアクセスする窓口
HTML構造、見た目、コンテンツを変更する
Virtual DOMとは
ブラウザのレンダリングと別管理、効率よくDOM操作できる。
通常のDOM操作の場合、
document.getElementById('hoge').innerText = 'fuga'
ReactのVirtualDOM操作
render(<div id='hoge'>fuga</div>)
差分描画について
変更されたVirtualDOMの差分を再描画するので、従来のHTMLをまるごと受け渡しするより早く描画できる。
JSXが使える
JavaScript内でHTMLっぽく書ける。
Reactの最大の強み。
JSXの基礎知識と文法
JSXとは
JavaScript内でHTMLを簡単に記述するための言語で、JavaScriptの拡張言語である。
Facebook社が開発していて、Reactの公式ドキュメントはほぼJSXで書かれている。
Reactでは業界標準である。
なぜJSXなのか (わかりにくいので後で書き直します)
通常のJavaScriptでHTMLを記述すると(DOM操作)
const fuga = '<h1>Hello,World!</h1>'
document.getElementById('hoge').innerHTML = huga
となる。
量が増えると、const foo='<h2>React Commentary</h2>
したあと、それのID、中身を変数で代入しなければならない。それをそれぞれやらなければならないので、わけわからなくなる。
JSXを使えばHTMLっぽく書けて可読性が高い。それだけでJSXを使う理由がある。
トランスパイラとは
翻訳のような役割。
JSXの構文はブラウザが理解出来ないので、トランスパイラで翻訳する必要がある。
例えば、JSXからJavaScript(ES6)など。
トランスパイラはBabel,CoffeeScript,TypeScriptなどが使われる。
もしJSXが無かったら
React.createElementを使う羽目になり、いちいちこれでHTMLを宣言しなければいけなくて面倒。
トランスパイラで翻訳されたあとはこのcreateElementが使われている。
基礎文法
Reactパッケージのインストールが必須。
.jsxファイルの先頭で宣言する。
import React from 'react'
HTMLとほぼ同じ記述
例外はある。
<div class='hoge'> → <div className='hoge'>
など。
{}内に変数や関数を埋め込める
const foo = <h1>Hello</h1>
{foo}
でHello
が表示できる。
つまり、{}内だけはJavaScriptの空間に出来る。
変数名などは全てキャメルケースで書く
javascriptなので、fooBar,classNameなど、ラクダのコブのように単語の区切りが大文字になる。
ハイフンで繋ぐケバブケースは使わない。foo-bar,class-nameなどは禁止。
空要素は必ず閉じる。
HTMLでは<input ~~~ >
でよいが、Reactでは<input ~~~ />
<img ~~~ />
のように、/>
で閉じる必要がある。
create-react-app
簡単に言うと
React開発環境をワン・コマンドで。
必要なもの
- node 8.10
- npm 5.6
- インストール用にhomebrewとnodebrew
なぜこれを使うのか
普通に環境構築しようとすると、くっっっっっっっっそ難しい。
トランスパイラのbabelやバンドラのwebpackの設定が必要だからである。
熟練者でもこれは難しいらしい。
create-react-appで作成されるフォルダ
- src:コンポーネントを作るjsファイルを入れる
- public:htmlファイルや設定ファイルを入れる
- build:本番環境用のファイルを入れる
src(ソースフォルダ)の中身
js,cssをrootに書き換えて、publicのindex.htmlで出力する。
publicフォルダの中身
- favicon.ico:タブの左側のアイコン
- 画像ファイル
- manifest.json:ホーム画面に追加が出来る設定ファイル
buildフォルダの中身
srcの中に入ってたものを1つにまとめて入れてある。
まとめる役割を持つのがバンドラ(webpack)。
コマンド集
npm run build
srcとpublic内のファイルを1つにまとめて(バンドル)、buildディレクトリに出力する。
同時にトランスパイル(翻訳)もされている。
npm start
ローカルサーバーを起動してReactアプリを確認できる。
npm run eject
babelやwebpackの設定を変更する
その他の環境構築ツール
- Next.js : SSR,SSGが出来る。SEO対策に最適。これからどんどん流行るであろう今最もアツいフレームワーク。
- Gatsby : 静的ウェブサイトに使える。
コンポーネントの基本 データの受け渡しと再利用
最初に
コンポーネントとは見た目プラス機能ということ
なぜコンポーネントを使うのか
再利用するため
ボタンコンポーネントに引数を渡して(props)色んな場所で使う
分割統治するため
それぞれのコンポーネント同士は互いに関連しあわないことで管理しやすい(疎結合)
変更に強くするため
分割統治すると変更に強くなる。
コンポーネントを変更しても、他のコンポーネントには一切関係がない(アトミックデザイン)
コンポーネントの種類
- Class Component : クラスによって定義されたコンポーネント(React-Hooksがデファクトスタンダードになっている現在、ほぼ使われていないので注意)
- Functional Component : 関数型で定義されたコンポーネント
FunctionalComponentの特徴
- ES6のアロー関数で記述
- stateを持たない(stateless)
- propsを引数に受け取る
- JSXをreturnする。
ClassComponentの特徴
- React.Componentを継承
- ライフサイクルやstateを持つ
コンポーネントが出てくるときにどう動くか、消えるときにどう動くか、これをライフサイクルと言う。 - propsにはthisが必要
this.propsの意味は、このクラス内のporpsだよって意味 - renderメソッド内でJSXをreturnする
- 記述量が多い代わりに状態(state)を持てる
(最近はクラスコンポーネントを使わず、なるべくファンクショナルコンポーネントを使う。)
propsでデータを受け渡す
親コンポーネント
const Blog = () => {
return (
<div>
<Article title={'React'} />
</div>
);
}
子コンポーネント
const Article = (props) => {
return (
<div>
<h2>{props.title}</h2>
</div>
);
}
受け渡せるデータ型
{}内に記述する。
文字列、数値、真偽値、配列、オブジェクト、変数、何でも渡せる。
文字列は{}無しでもOK
再利用する
コンポーネントを使い回す。
<Articl title={'React'} />
<Articl title={'JSX'} />
コンポーネントの状態 stateの設定と取得と変更
状態(state)とは
- コンポーネント内で管理する変数
- ローカルステートと呼ばれる。(reduxではグローバルステートがある。)
- propsとして子コンポーネントに渡せる。
なぜstateを使うのか
- render()内で値を変更してはいけないから。 (stateが変わると再レンダーされる。その際にまたstateが変わって再レンダーされる。以下無限ループ)
- setState()で値を変更する。
- stateの変更=再レンダーのきっかけ ページリロードせず表示を切り替えられる。
stateの設定方法
- ClassComponentが前提
- constructor()内で宣言
- オブジェクト型で記述
constructor(props) {
super(props);
this.state = {
isPublished: false }}
stateの取得
- 同コンポーネント内ならthis.state.key名で取得できる
- 子コンポーネントで参照したい場合はpropsで渡す
-
<Article title='React' isPublished={this.state.isPublished} />
で渡せる
stateの変更方法
- setState()を使う
- 関数にラップするのが一般的
- setState()内に記述されたstateのみを変更
- 公開状態を反転させる関数を定義する
togglePublished = () => {
this.setState({
isPublished: !this.state.isPublished }) };
// ここの!は反転させるの意味
コンポーネントのライフサイクル 副作用のある処理を書こう
ライフサイクルとは
- コンポーネントの時間の流れ
- 生まれて、成長して、死ぬまでの循環
- それぞれの段階で必要な処理を記述
- Reactの基礎中の基礎
3種類のライフサイクル
- Mounting : コンポーネントが配置される(生まれる)期間
- Updating : コンポーネントが変更される(成長する)期間
- Unmounting : コンポーネントが破棄される(死ぬ)期間
なぜライフサイクルを使うのか
- 関数の外に影響を与える関数を記述するため DOM変更、API通信、ログ出力、setState()など
- 副作用=適切な場所に配置すべき処理
それぞれの期間
- Mounting→constructor()→render()→componentDidMount()
- Updating→render()→componentDidUpdate()
- Unmounting→componentWillUnmount()
主要メソッド(Mount)
- constructor() : 初期化(stateなど)
- render() : VDOMを描画(JSXをリターン)
- componentDidMount() : render()後に1度だけ呼ばれる。リスナーの設定やAPI通信に使われる
主要メソッド(Update)
- render() : VDOMを再描画
- componentDidUpdate() : 再render()後に呼ばれるスクロールイベントや条件付きイベント 例(新しいコメントが入ってきたときに、そこにスクロールするなど。)
主要メソッド(Unmount)
- componentWillUnmount() : コンポーネントが破棄される直前にリソースを開放するため リスナーの解除など。API通信の解除など。
importとexport モジュールを使いこなす
モジュール化とは
- 多言語では昔からある概念
- JavaScriptではES6から
- 基本的に1ファイル1モジュール
- 任意の場所で読み込める
モジュール化の威力
- 分割統治できる : 大規模プログラムでも管理しやすい
- 任意の場所で読み込める : 必要なものを必要な分だけ
- 再利用ができる : 何度も同じコードを書かなくてよい
- Reactはモジュール化を強く推奨してる
名前付きexport
- 1モジュールから複数の関数をexport
- クラスはexportできない
export funcrion 関数名(){}
export const 関数名 = () => {}
名前無し(default)export
- 1ファイル(1モジュール)1export
- ES6で推奨方法
- アロー関数は宣言後にexport
- クラスをexportできる
モジュール全体のimport
- 名前無し(default)exportしたモジュールをimportする
- モジュール全体のimport
関数ごとのimport
- 名前付きexportされたモジュールをimportする
- {}内にimportしたい関数名
別名import
- 別名(エイリアス)をつけてimportできる
- モジュール全体なら
* as name
- モジュール一部なら
{A as B}
ReactHooks 関数コンポーネントでもステートを使おう
フックとは
- クラスの機能を関数コンポーネントでも使える
- React16.8から導入
- 100%後方互換だから小さく導入できる
なぜフックを使うのか
- シンプルさを保つため
- クラスコンポーネントは難しい
- thisという悪魔 : JavaScriptでは他の言語のthisとは違う挙動をする
- stateを扱うロジックが複雑
- 複数のライフサイクルメソッドに副作用のある処理がまたがる : componentDidMountでイベントリスナーを設定して、componentDidUnmountで解除する。この記述をまとめたい。
- これらを解決するのがフック
useState()を使おう
- ステートフックと呼ばれる
- クラスコンポーネントでいう
this.state
とthis.setState()
を代替する - 複数のstateを扱うときはstateごとに宣言
useState()の使い方
1. useState関数をインポート : import React,{useState} from 'react;
2. 宣言する : const [isPublished, togglePublished] = useState(false);
左から順に「state変数名」、「state変更関数名」、「state初期値」
3. JSX内で使う : <input ~~~ onClick={() => togglePublishec(!isPublished)} />
ReactHooks 関数コンポーネントでもライフサイクルを使う
useEffect()のメリット
- ライフサイクルメソッドを代替出来る
- 関数コンポーネントでライフサイクルを使える
- コードをまとめられる
- 機能ベースがよい(何をやっているのかわかる)
- 時の流れベースはよくない(ライフサイクルのメソッドごとがわかりづらい)
useEffect()の仕組み
- レンダー毎にuseEffect()内の処理が走る
- 代替出来るメソッドは以下
- componentDidMount
- componentDidUpdate
- componentDidUnmount
パターン1 レンダーごと
- 基本の形
- useEffect()内にCallback関数を書く
- Callbackはレンダー毎に呼ばれる
- returnするCallback関数はアンマウント時に呼ばれる(クリーンアップ関数)
useEffect(() => {
console.log('Render!')
return () => {
console.log('Unmounting!')}})
パターン2 マウント時のみ
- 第2引数の配列内の値を前回レンダーと今回レンダーで比較 : 変更があればCallback関数を実行
- 第2引数に空の配列を渡すと最初の1回のみ実行される
useEffect(() => {
console.log('Render!')}, [] )
パターン3 マウントとアンマウントのみ
- 1と2の複合系
- 通常のCallbackはマウント時のみ
- アンマウント時はreturn内のクリーンアップ関数が実行
useEffect(() => {
console.log('Render!')
return () => {
console.log('Unmounting!)} }, [] )
パターン4 特定のレンダー時
- マウント時に実行される
- limitの値が変わったときに実行される
- 例えば、limitの値がtrueからfalseになったとき。
const [limit, release] = useState(true);
useEffect(() => {
console.log('Render!') }, [limit])