はじめに
普段サーバサイドをメインでやっているのですが、つい最近プロジェクトでReactを使う機会があり、一度は挫折したReduxを使いました。
メモのつもりでしたが、
「現在Reactを触ってて、Reduxも使いたい」
「Reduxでやりたいことはなんとなく分かるけど使い方がイマイチ分からない」
って方の助けになれればと思い、React + Redux の使い方をざっとまとめました。
Reduxとは
Reactが扱うUIのstate(状態)を管理をするためのフレームワークです。
詳しくはここでは説明しませんが、色々ググれば詳しいことは書いてあります。
サンプル(イメージ)
今回は入力フォームにテキスト(名前)を入力して、それを出力するといったごく簡単なものです。
できる限りわかりやすいように簡単なものにしました。
デモページ
準備(インストール)
まず、create-react-app
でReactアプリを作成します。
続いてredux
とreact-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のタイプの名前を定義します。
export const SEND_NAME = 'SEND_NAME'
アプリケーションが大きくなることを踏まえて、別ファイルに記述しています。
今回は一つだけですが、複数のActionがある場合は複数記述してください。
Actionのタイプはあなた次第です。
続いて実際にActionを定義します。
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;
}
}
まとめると下記のようになります。
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を分けています。
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);
もしもログを出したい場合は下記のようにしてください。
今回は開発環境のみにログを出します。
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を作成します。
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で書き込んだ値を取得する処理を書きます。
export const getNameStore = store => store.name;
export const getName = store =>
getNameStore(store) ? getNameStore(store).name : 'No Name';
続いてJSXを作成します。
こちらもconnect
と、先ほど作成したファイルを読み込みます。
MapStateToProps
で取得する処理を書き、connectの第一引数で呼び出します。
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での開発がすごく変わります!
是非トライしてみましょ!