7
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

挫折しないで!作って学ぶ React + Redux 入門【実践】

Last updated at Posted at 2020-01-24

はじめに

普段サーバサイドをメインでやっているのですが、つい最近プロジェクトでReactを使う機会があり、一度は挫折したReduxを使いました。
メモのつもりでしたが、
「現在Reactを触ってて、Reduxも使いたい」
「Reduxでやりたいことはなんとなく分かるけど使い方がイマイチ分からない」
って方の助けになれればと思い、React + Redux の使い方をざっとまとめました。

Reduxとは

Reactが扱うUIのstate(状態)を管理をするためのフレームワークです。
詳しくはここでは説明しませんが、色々ググれば詳しいことは書いてあります。

サンプル(イメージ)

今回は入力フォームにテキスト(名前)を入力して、それを出力するといったごく簡単なものです。
できる限りわかりやすいように簡単なものにしました。
demo.gif
デモページ

準備(インストール)

まず、create-react-app でReactアプリを作成します。
続いてreduxreact-redux をインストールします。

$ npm install --save redux react-redux

開発時にreduxのログを出力したい場合は、redux-loggerもインストールします。

$ npm install --save redux-logger

構成

src/
 ├── components/
 │       ├── ui/
 │       │    ├── SendName.jsx
 │       │    └── GetName.jsx
 │       └── App.jsx
 ├── redux/
 │     ├── reducers/
 │     │      ├── index.js
 │     │      └── name.js
 │     ├── action.js
 │     ├── actionTypes.js
 │     ├── selectors.js
 │     └── store.js
 └── index.js

Redux

1. Actions

Actions は、アプリケーションからstoreにデータを送信する情報のオブジェクトです。

まずはじめにActionのタイプの名前を定義します。

~/redux/actionTypes.js
export const SEND_NAME = 'SEND_NAME' 

アプリケーションが大きくなることを踏まえて、別ファイルに記述しています。
今回は一つだけですが、複数のActionがある場合は複数記述してください。
Actionのタイプはあなた次第です。

続いて実際にActionを定義します。

~/redux/action.js
import { SEND_NAME } from 'redux/actionTypes'

export const sendName = name => ({
  type: SEND_NAME,
  name: name
});

ここで注意なのがtype は必ず入れてください。
あとは自分が開発するアプリケーションに合わせて定義してください。
今回は入力される名前だけなのでname だけ定義しています。

2. Reducers

Reducers は、storeに送信されたActionsに応じてアプリケーションの状態がどのように変化するかを指定するメソッドを定義します。

まずはじめに初期状態を定義します。

const initialState = {
  name: ''
};

つづいてActionのタイプに応じて処理を書いていきます。
複数のActionを定義している場合はタイプに応じて処理を書いてください。

export default (state = initialState, action) => {
  switch (action.type) {
    // case Actionタイプ名
    case SEND_NAME:
      return {
        ...state,
        name: action.name
      };
    default:
      return state;
  }
}

まとめると下記のようになります。

~/reducers/name.js

import { SEND_NAME } from 'redux/actionTypes'

const initialState = {
  name: ''
};

export default (state = initialState, action) => {
  switch (action.type) {
    case SEND_NAME:
      return {
        ...state,
        name: action.name
      };
    default:
      return state;
  }
}

最後に定義したReducerを呼び出し一つのオブジェクトにします。
これもアプリケーションが大きくなることを踏まえてReducerを分けています。

~/reducers/index.js
import { combineReducers } from 'redux'
import name from 'redux/reducers/name'

export default combineReducers({name});

3. Stores

続いてStores を定義します。
Reduxではstoreは必ず一つにしてください。

import { createStore } from 'redux'
import rootReducer from 'redux/reducers'

export default createStore(rootReducer);

もしもログを出したい場合は下記のようにしてください。
今回は開発環境のみにログを出します。

~/redux/store.js
import { createStore, applyMiddleware } from 'redux'
import rootReducer from 'redux/reducers'
import { createLogger } from 'redux-logger'

const middlewares = [];

if(process.env.NODE_ENV !== 'production') {
  const logger = createLogger({
    diff: true,
    collapsed: true,
  });
  middlewares.push(logger);
}

const store = createStore(rootReducer, applyMiddleware(...middlewares));

export default store;

React + Redux

続いてReactからReduxを操作します。

書き込み

まずはじめに入力した値(名前)をReduxで宣言したname に書き込みます。
書き込む際は、

  • ReactとReduxを繋ぐ為のconnect
  • 使用したいAction

を読み込みます。

import { connect } from 'react-redux'
import { sendName } from 'redux/action'

続いてconnect を使いReactとReduxを繋ぎます。

connect(mapStateToProps, mapDispatchToProps)(App);
  • 第一引数mapStateToPropsは、componentに渡すpropsを制御します
  • 第二引数のmapDispatchToPropsは、reducerを呼び出して、reduxで管理しているstateを更新します
  • Appは、取得したデータをpropsとして扱いたいcomponentを指定します

では、さっそく書き込み用のJSXを作成します。

~/components/ui/SendName.jsx
import React, { Component }  from 'react'
import { connect } from 'react-redux'
import { sendName } from 'redux/action'

class SendName extends Component {
  constructor(props) {
    super(props);
    this.state = {name: ''};
  }

  updataName = name => {
    name = name.trim();
    this.setState({ name });
  };

  handleSendName = () => {    
    this.props.sendName(this.state.name);
    this.setState({name: ''});
  };

  render() {
    return (
      <div className={Style.form}>
        <label htmlFor='name'>
          名前
          <input type='text' onChange={e => this.updataName(e.target.value)} value={this.state.name}>
        </label>
        <button onClick={this.handleSendName}>送信</button>
      </div>
    );
  }
}

export default connect(null, {sendName})(SendName);

読み込み

まずはじめにReduxで書き込んだ値を取得する処理を書きます。

~/redux/selectors.js
export const getNameStore = store => store.name;

export const getName = store =>
  getNameStore(store) ? getNameStore(store).name : 'No Name';

続いてJSXを作成します。
こちらもconnectと、先ほど作成したファイルを読み込みます。
MapStateToPropsで取得する処理を書き、connectの第一引数で呼び出します。

~/components/ui/GetName.jsx
import React from 'react'
import { connect } from 'react-redux'
import { getName } from 'redux/selectors'

const GetName = ({name}) => {
  return (
    <p>入力された名前{name}</p>
  );
}

const MapStateToProps = state => {
  const name = getName(state);
  return {name};
}

export default connect(MapStateToProps)(GetName);

これでReact + Reduxでstate(状態)を管理できます。

さいごに

Reduxは理解するまで少し大変だと思いますが、是非手を動かしながら学んでみてください。
Reduxが使えればReactでの開発がすごく変わります!
是非トライしてみましょ!

コード

参考

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?