fluxのフレームワークの一種。 dispatcherが無いがないため、完全なfluxフレームワークとは言えない。
redux http://rackt.github.io/redux/index.html
react-redux https://github.com/rackt/react-redux
http://qiita.com/kompiro/items/7ddca41bef00444e14c7
https://github.com/rackt/redux/tree/master/examples/counter
webpackで静的ファイルの結合生成を行っている。 nodeで結合させている事前に結合処理をしていない。
https://github.com/pompopo/electron-boilerplate
babelでjsのcompileを動的に行っている index.htmlの中でrequire('babel/register’)を呼び出している
babel/registerはRequire hook用のモジュールで、mocha以外でも動く。 あらゆるrequire()の前にrequire('babel/resgiter')しておけば、その後のrequire()はBabelのパーサーを通って解決される。
参考: http://blog.axross.org/entry/2015/03/14/171113
エントリポイントとなるモジュールファイルだけrequireを通して あとはbabelなのでes6でかけば良い requireではなくimportで書けば良い
※electronの場合アプリ内にnode_moduleが含まれるので コンパイルしてbundle.jsファイルを別途つくる必要がない(distributionする必要無し) node.jsと同じ考え方でいいっぽい
https://github.com/hokuma/react-redux-async-sample
reducerを設定しstoreに結合させる
reducerのモジュール部分 ここに処理を書いている。
import { combineReducers } from 'redux'
import hogeCounter from './counter'
const rootReducer = combineReducers({
hogeCounter
});
export default rootReducer;
counterに実処理を書いて、reduxモジュールのcombineReducersを使って結合させる
counter実処理部分 counterは単なるメソッド
import { INCREMENT, DECREMENT } from '../actions/counter';
export default function counter(state=0, action) {
switch(action.type) {
case INCREMENT:
return state + 1;
case DECREMENT:
return state - 1;
default:
return state;
}
}
actionを受けて処理を変える
引数stateは独自設定が出来る
//recducerのstateの定義は独自で行う。
//stateの値はreducer内にそのまま引き継がれる
var initialState = {
counter: 0
};
//ここでstateにcounterの値が入ってくるのがわからない
export default function counter(state = initialState, action) {
// console.log("#reducer counter = " + state);
console.log(state)
var a = 0;
switch (action.type) {
case INCREMENT_COUNTER:
return {
counter:state.counter+1
};
case DECREMENT_COUNTER:
return {
counter:state.counter-1
};
default:
return state;
}
}
※todo確認:メインメソッドは一つとして処理を別メソッドで設定したい場合はどうなるのか?
storeにreducerを設定する
let store = applyMiddleware(thunk)(createStore)(rootReducer);
React.render(
<Provider store={store}>
{() => <Root />}
</Provider>,
document.getElementById('root'))
別サンプルバージョン
const createStoreWithMiddleware = applyMiddleware(
thunkMiddleware
)(createStore);
const store = createStoreWithMiddleware(rootReducer);
store.dispatch(getTodosIfNeeded());
React.render(
<Provider store={store}>
{function() { return <TodoApp /> }}
</Provider>,
document.getElementById('todo-app')
);
こちらではstoreにaction発行処理をdispatchされるように設定している stateとmethodを受け渡すようにする
action部分
export function increment() {
return {
type: INCREMENT
};
}
export function decrement() {
return {
type: DECREMENT
};
}
export function async_increment() {
return dispatch => {
setTimeout(() => {
dispatch(increment());
}, 1000);
}
}
componentとアクション部分をdispatchで結合させる
mapStateToPropsの引数stateの中身はreducerの定義で指定したconbineのモジュールが入る この例ではcounterだったのでproperty名がcounterになる
function mapStateToProps(state) {
return {
count: state.hogeCounter
};
}
// Which action creators does it want to receive by props?
function mapDispatchToProps(dispatch) {
return {
increment: () => dispatch(increment()),
decrement: () => dispatch(decrement()),
async_increment: () => dispatch(async_increment()),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(Root);
reduxモジュールのbindActionCreatorsを使って設定する方法もあり。
import { bindActionCreators } from 'redux';
function mapStateToProps(state) {
return {
counter: state.counter
};
}
function mapDispatchToProps(dispatch) {
return bindActionCreators(CounterActions, dispatch);
}
export default connect(mapStateToProps, mapDispatchToProps)(Counter);
ボタンを押す
provider経由でわたって来てるpropsにわたって来てるstore = reducerのメソッドを実行する。
大本のレンダリング
React.render(
<Provider store={store}>
{() => <Root />}
</Provider>,
document.getElementById('root'))
実行ポイント
<button onClick={this.props.increment}>Increment</button>
メソッドの実行で予め実装していたメソッドでaction発行、reducerに通知しstate変更される。
http://qiita.com/kompiro/items/7ddca41bef00444e14c7 http://qiita.com/kompiro/items/7fe90c4abc92fd32b343