Reduxとは
Reduxとは状態管理をするライブラリ
Reactでは様々なコンポーネントの状態が個別で扱われるが、それらを統合して管理する機能を提供している
特徴
- すべてのデータはアプリケーションごとに1つだけ用意されるStoreに保管される
- Storeの値は読み取り専用で、直接書き換えは許可されていない
- Storeの値を変更するにはReducerを使う
インストール
Reduxのインストール
npm install --save redux
React Reduxのインストール
npm install --save react-redux
Reduxで用意するもの
Store
データを保管し管理する
ここに保管される値はstateと呼ばれる
Storeの中にstateとReducerが組み込まれているイメージ?
Provider
Storeを他のコンポーネントに受け渡す
Reducer
Storeに保管されるstateを変更する
実際に使っていく
今回はボタンを押すと数字が1ずつ増えていくものを作っていく
create-react-appコマンドで雛形を作る
create-react-app ディレクトリ名
create-react-appコマンドをインストールしてない場合は下記のコマンドでインストールする
npm install -g create-react-app
サーバーを起動する
npm start
または
yarn start
ディレクトリ構造
ディレクトリ構造は下記のように編集しました
srcの中にcomponentsを作成し、App.js, Button.js, Message.js, Store.jsがあるだけです
│ ├── src │ ├── .DS_Store │ ├── App.css │ ├── App.test.js │ ├── components │ │ ├── App.js │ │ ├── Button.js │ │ ├── Message.js │ │ └── Store.js │ ├── index.css │ ├── index.js │ └── serviceWorker.js
index.js
index.jsを下記のように下記のように書き換える
import React from 'react'; import ReactDOM from 'react-dom'; import { Provider } from 'react-redux'; import './index.css'; import App from './components/App'; import countStore from './components/Store' import * as serviceWorker from './serviceWorker'; ReactDOM.render( <Provider store={countStore}> <App /> </Provider>, document.getElementById('root') ); serviceWorker.unregister();
Providerタグの中にコンポーネントを記述するとことで、
内部のコンポーネントでストアに保管されている値や処理が使えるようになる
Store.js
ここにストアを記述していく
import { createStore } from 'redux'; //ステート const state_value = { count: 0, }; // レデューサー function countReducer(state = state_value, action) { switch (action.type) { case 'INCREMENT': return { count:state.count + 1, }; default: return state; } } //createStoreでストアを作成しエクスポート export default createStore(countReducer);
stateの用意
ストアに保管するステートの値を用意する
今回は数字をカウントするcountを用意
//ステートの用意 const state_value = { count: 0, };
Reducerの作成
function 関数名(state = 先ほど作成したstate名, action)
第一引数のstateには、ストアに保管するstateを指定する
第二引数のactionはReducerを呼び出した時の情報が保管され、
さらにtypeというプロパティが必ず用意される
次にswitchによる条件分岐を記述
// レデューサーの作成 function countReducer(state = state_value, action) { switch (action.type) { //typeがINCREMENTだった場合の処理 case 'INCREMENT': return { count:state.count + 1, }; default: return state; } }
Reducerは条件分岐
action.typeの値をチェックして
それぞれの値に応じて処理を行なってreturnする
Storeの作成
createStoreという関数で作成する
引数にはReducerを指定
export default createStore(countReducer);
App.js
import React from 'react'; import { connect } from 'react-redux'; import '../App.css'; import Message from './Message'; import Button from './Button'; class App extends React.Component { render() { return ( <div> <h1>Redux</h1> <Message /> <Button /> </div> ); } } export default connect()(App);
Storeのconnect
App, Message, Buttonの3つのComponentに記述している
connectはComponentにStoreを接続するための関数
connent(設定する内容)(Component);のように記述
1つ目の()には、接続する際にstateなどに設定する値を用意
2つ目の(には、コネクトするコンポーネントを用意
export default connect()(App);
App.jsではStoreの値は利用しないので,
1つ目の()の引数は何も無し
Message.js
import React from 'react'; import { connect } from 'react-redux'; import '../App.css'; // カウント表示のコンポーネント class Message extends React.Component { render(){ return ( <p> {this.props.count} </p> ); } } // ストアのコネクト export default connect((state)=>state)(Message);
Storeのconnect
1つ目の()の引数でstateをそのまま返すアロー関数を指定して
Messageコンポーネントにコネクトし、それをそのままexport defaultすることで
Messageをimportしたら、コネクトされたMessageが使えるようになる
export default connect((state)=>state)(Message);
Button.js
import React from 'react'; import { connect } from 'react-redux'; import '../App.css'; class Button extends React.Component { constructor(props){ super(props); this.doAction = this.doAction.bind(this); } // ボタンクリックでディスパッチを実行 doAction(e){ this.props.dispatch({ type:'INCREMENT' }); } render(){ return ( <button onClick={this.doAction}> click </button> ); } } // ストアのコネクト export default connect()(Button);
dispatch
dispatchはReduxにactionを送る働きをする
dispatchによってactionが送られると、StoreのReducerが呼び出されて
そこで、必要な処理が実行される
actionのtypeの値をチェクしINCREMENTの時はcountを+1する
this.props.dispatch({ type:'INCREMENT' });
最後に
今回のソースコードはこちらにもあります
GitHub - TakaShinoda/CountUP