React/Reduxメモ

## React

### Reactとは
公式ドキュメント： https://ja.reactjs.org/
- Facebook製のJSライブラリ
- JSXという独自の記法を用いる
- Angular/Vueと並ぶ3大JSライブラリの1つ

---

### JSXとは
- JSとHTMLが合わさったようなもの


```jsx
import React from 'react';

render() {
  return (
    <div>
      <span>テスト</span>
      <span>JSX</span>
    </div>
  );
}
```

---

### propsとは
- 親コンポーネントから渡されたプロパティ
例：ObjectDetailPageというコンポーネントを呼び出すとき

```jsx
　<ObjectDetailPage objectDetail={objectDetail} />
```

このように書くとobjectDetailはObjectDetailPageコンポーネントでpropsとして扱われる

---

### stateとは
- そのコンポーネント内でのみ使用するローカル変数のようなもの
- setState関数を使用して値を変更する
- setState関数を使用して値を変更するとrender関数が呼び出される

--- 

### ライフサイクルメソッドとは
公式ドキュメント： https://ja.reactjs.org/docs/react-component.html

---

### よく使うライフサイクルメソッド
- render：必須のメソッド 画面にレンダリングする要素を書く
- componentDidMount： コンポーネントマウント後に1度だけ実行される
    - 画面描画に必要な情報を取得するAPI呼び出し処理を書いたりする
- componentDidUpdate：更新される度に実行される
    - 例：更新前にIDがなく更新後にIDがある場合、更新されたフラグをtrueにする 等
- componentWillUnmount：コンポーネントアンマウント前に実行される
    - removeEventListenerを書いたりする Reduxも使用している場合不要な値を初期化する処理を書いたりもする
- shouldComponentUpdate：renderを呼ぶかどうか判定する
    - stateの値を更新したいが画面に変更を反映させたくない場合等に使う

---

### サンプルコード

```jsx
import React from 'react';

export default class ObjectDetailPage extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      objectDetail: null
    };
  }

  componentDidMount() {
    // オブジェクト詳細取得APIを叩く
    const objectDetail = axios
      .get('https://api.test.co.jp/object')
      .then(response => {
        return response;
      })
      .catch(error => {
        console.log(error);
      });
    // APIのレスポンスをコンポーネントのstateに設定
    this.setState({ objectDetail });
  }

  render() {
    const { objectDetail } = this.state;
    if (!objectDetail) {
      // componentDidMount実行前はこの分岐に入る
      return null;
    }
    return (
      <div>
        <span>ID：{objectDetail.id}</span>
        <span>名前：{objectDetail.name}</span>
      </div>
    );
  }
}
```

---

### メリット
- JSXの構文がHTMLに似ているため初めてでも読み書きしやすい
    - HTMLのタグがほとんど同じように使える
- ライブラリが豊富で難しい実装も簡単にできたりする
    - 例：画像遅延読み込み用ライブラリ、GoogleMapAPIを利用するライブラリ
- Javascriptと比べると全体的にかなりスマートに書ける
    - ライフライクルメソッドをうまく使うとより綺麗に
- 描画が早い
    - 差分だけ描画するので早い

---

### デメリット
- Props、State等の概念が少しわかりづらい？
- ライフサイクルメソッドの動きを覚えないと処理を追うのが大変
- 英語の文献が多い（最近は公式ドキュメントが日本語になった）
- 環境を作るのが大変（らしい） Node.js、babel、webpack等…
- ES6の書き方を覚える必要がある（let・constやアロー関数等）


------------------------

## Redux

### Reduxとは
公式ドキュメント：https://redux.js.org/
- UIのstate(状態)を管理をするためのフレームワーク

---

### storeとは
- アプリケーション全体のデータ（state）を格納しておく場所

---

### actionとは
- reducerに対して何をするか指定するオブジェクト
- これをstoreのインスタンスに送信（dispatch）するとstoreのstateが更新される


```javascript
// objectDetailの値を更新するaction
{
  type: 'SET_OBJECT_DETAIL',
  objectDetail: { id: 1, name: 'テスト' }
},
// objectDetailの値を初期化するaction
{
  type: 'INIT_OBJECT_DETAIL'
}
```

---

### reducerとは
- storeから受け取ったactionとstateに応じて、変更されたstateを返す関数

```javascript
function testReducer(state = { objectDetail }, action) {
  switch (action.type) {
    case 'SET_OBJECT_DETAIL':
      // objectDetailを渡された値で更新する
      state.objectDetail = action.objectDetail;
      return state;
    case 'INIT_OBJECT_DETAIL':
      // objectDetailを初期化する
      state.objectDetail = { id: 0, name: '' };
      return state;
    default:
      return state;
  }
}
```

---

### Reactと合わせて使う
- ObjectDetailPage: Reactコンポーネント

```jsx
import { connect } from 'react-redux';
import ObjectDetailPage from 'src/components/ObjectDetailPage'

const mapStateToProps = state => {
  // storeのobjectDetailをコンポーネントのpropsに設定する
  return { objectDetail: state.objectDtail };
};

export default connect(mapStateToProps)(ObjectDetailPage);
```

---

### mapStateToProps関数とは
- storeのstateをコンポーネントのpropsとして扱えるようにする関数
    - 要約：コンポーネントで使いたいstoreの値を設定する関数

---

### mapDispatchToProps関数とは
- 関数をコンポーネントのpropsとして扱えるようにするもの
    - 要約：storeの値をコンポーネントから変更するための関数を設定する関数
- connect関数の第2引数として渡す
下記例のように書くと、ObjectDetailPageコンポーネントで`this.props.initObject()`としてobjectDetailの初期化処理を呼び出すことができる

```jsx
import { connect } from 'react-redux';
import ObjectDetailPage from 'src/components/ObjectDetailPage'

const mapStateToProps = state => {
  // storeのobjectDetailをコンポーネントのpropsに設定する
  return { objectDetail: state.objectDtail };
};

const mapDispatchToProps = dispatch => {
  // objectDetail初期化処理をコンポーネントのpropsに設定する
  return { initObject => dispatch({ type: 'INIT_OBJECT_DETAIL' }) };
};

export default connect(mapStateToProps, mapDispatchToProps)(ObjectDetailPage);
```

---

### サンプルコード
サンプルコードはReduxを使うほどの規模ではないので使うメリットがわかりづらいかも…

```jsx
import React from 'react';
import { connect } from 'react-redux';

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

  componentDidMount() {
    const { setObjectDetail } = this.props;
    // オブジェクト詳細取得APIを叩く
    const objectDetail = axios
      .get('https://api.test.co.jp/object')
      .then(response => {
        return response;
      })
      .catch(error => {
        console.log(error);
      });
    // APIのレスポンスをstoreに設定
    setObjectDetail(objectDetail);
  }

  componentWillUnmount() {
    const { initObject } = this.props;
    // storeの値を初期化
    initObject();
  }

  render() {
    const { objectDetail } = this.props;
    if (!objectDetail) {
      // componentDidMount実行前はこの分岐に入る
      return null;
    }
    return (
      <div>
        <span>ID：{objectDetail.id}</span>
        <span>名前：{objectDetail.name}</span>
      </div>
    );
  }
}

const mapStateToProps = state => {
  // storeのobjectDetailをコンポーネントのpropsに設定する
  return { objectDetail: state.objectDetail };
};

const mapDispatchToProps = dispatch => {
  // SET_OBJECT_DETAILとINIT_OBJECT_DETAILをコンポーネントのpropsに設定する
  return {
    getObject: objectDetail => dispatch({ type: 'SET_OBJECT_DETAIL', objectDetail }),
    initObject: () => dispatch({ type: 'INIT_OBJECT_DETAIL' })
  };
};

export default connect(mapStateToProps, mapDispatchToProps)(ObjectDetailPage);
```

---

### メリット
- 複数のページで共通のデータを利用できる
    - 例：一覧ページでオブジェクトの情報を取得したら、詳細ページでもその情報をそのまま使える
- Reactとの相性が良い らしい（他と合わせて使ったことがないので…）

---

### デメリット
- 学習コストが高め
    - action？dispatch？reducer？　動きが分からないと全く処理が追えないレベル