初投稿ながらも、頑張って書いてみました。
小規模な開発をする上で、生のReactに不満はなかったのですが、今後のスキルアップのために「Redux」について触れていきたいと思います。
##Redux について
Reactだけでも、フロントエンドの開発はできます。
Reactと独自実装でも状態管理はできますが、いい感じに状態管理周りをまとめてくれるフレームワークの一つが Redux です。
##Reduxの導入
###react用モジュール
・react
・react-dom
###redux連携用モジュール
・redux
・react-redux
{
"name": "react-redux-tutorial-counter",
"version": "1.0.0",
"description": "Sample app",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "browserify src/index.js -o dist/bundle.js -t [ babelify --presets [ react es2015 ] ]"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"browserify": "12.0.1",
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babelify": "^7.2.0"
},
"dependencies": {
"react": "^15.0.1",
"react-dom": "^15.0.1",
"react-redux": "^4.4.2",
"redux": "^3.4.0"
}
}
##Reduxを構成するコンポーネントの種類
今回出てくるコンポーネントは下記の二つです。
①Provider
Providerコンポーネントはreact-reduxが提供する実在するReactコンポーネントです。
唯一、Storeを持つことを許された存在で、Stateやdispatch関数を配下のContainerコンポーネントで利用可能にします。
②Container
Containerは connect関数でReactコンポーネントをラッピングしたものです。
##フォルダ構成
###・dist
コンパイルしたものをここのディレクトリに出力します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Redux</title>
</head>
<body>
<div id="root"></div>
<script src="bundle.js"></script>
</body>
</html>
###・src
srcはactions, components, containers, reducers, storeから構成されます。
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import configureStore from './store/configureStore';
import App from './containers/app';
const store = configureStore();
ReactDOM.render(
//ストアを作ってproviderに渡す。
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
index.htmlの中のroot要素に、Reactで生成したDOMを流し込む。
store
import { createStore } from 'redux';
import reducer from '../reducers/index';
export default function configureStore() {
const store = createStore(reducer);
return store;
}
Storeを作成する際に、ReducerをcreateStore()メソッドの第一引数として渡すことで、Store内でstateの更新が可能になります。
また、ReduxにはMiddlewareという概念があり、必要に応じてMiddlewareを追加することで、非同期処理が可能になったり、Stateのログを見れるようになります。
actions
export default {
increment: () => {
return { type: 'INCREMENT' }
},
decrement: () => {
return { type: 'DECREMENT' }
}
}
actionはStateを変えるためやAPIを叩くときに、Viewから呼ばれます。
actionTypeを付与することで、reducerでどのようにStateが変更されるのかを区別します
reducers
// 初期ステート設定
const initialState = {
fuga: 0
}
// actionに応じてステート変更
export default function reducer(state = initialState, action) {
switch (action.type) {
case 'INCREMENT': {
return { fuga: state.fuga + 1 }
}
case 'DECREMENT': {
return { fuga: state.fuga - 1 }
}
default:
return state
}
}
state の状態を更新するためのロジックを書く部分。
containers
import React from 'react'
import { connect } from 'react-redux'
import App from '../components/app'
import AppActions from '../actions/app'
function mapStateToProps(state) {
return state
}
// clickでactionを飛ばず
function mapDispatchToProps(dispatch) {
return {
Increment_Click: () => { dispatch(AppActions.increment()) },
Decrement_Click: () => { dispatch(AppActions.decrement())}
}
}
export default connect(//これが子コンポーネントで使える要素(props)
mapStateToProps,
mapDispatchToProps
)(App)
mapStateToProps関数とmapDispatchToProps関数は、それぞれStoreのstateとdispatchメソッドをpropsを通して、Containerで扱えるようにするものです。
components
import React from 'react';
//reduxやactionsをimportしていない。→ 必要なモノは親から全てprops経由で受け取っている
export default class App extends React.Component {
render() {
return (
<div>
<span>{this.props.fuga}</span><br/>
<button onClick={ () => this.props.Increment_Click() }>*増加*</button>
<button onClick={ () => this.props.Decrement_Click() }>*減少*</button>
</div>
);
}
}
##ビルドする
npm run build
dist下にbundle.jsが生成されるので、最初に作ったindex.htmlにアクセスします。
##参考にさせていただきました
React + Redux入門初歩 実際に一からアプリを構築してみる