はじめに
こちらに記載があるように、
From the very beginning, we need to stress that Redux has no relation to React. You can write Redux apps with React, Angular, Ember, jQuery, or vanilla JavaScript.
ReactとReduxはそれぞれ独立している。ただ、組み合わせて使うことは一般的であるため、ReactReduxというReduxをReactにバインドさせるためのライブラリがある。そしてこのライブラリは、connect
とProvider
というAPIを提供している。
ReactReduxの使用前後のコードを比較する
まずは、使用前後のコードを並べる。
connect
これが
class VisibleTodoList extends Component {
componentDidMount () {
const { store } = this.context;
this.unsubscribe = store.subscribe(() =>
this.forceUpdate()
);
}
componentWillUnmount() {
this.unsubscribe();
}
render () {
const props = this.props;
const { store } = this.context;
const state = store.getState();
return (
<TodoList
todos={
getVisibleTodos(
state.todos,
state.visibilityFilter
)
}
onTodoClick={id =>
dispatch({
type: TOGGLE_TODO,
id
})
}
/>
)
}
}
VisibleTodoList.contextTypes = {
store: React.PropTypes.object
}
こうなる
/*
* VisibleTodoList
*/
const mapStateToProps = (state) => {
return {
todos: getVisibleTodos(
state.todos,
state.visibilityFilter
)
};
};
const mapDispatchToProps = (dispatch) => {
return {
onTodoClick: (id) =>{
dispatch({
type: TOGGLE_TODO,
id
});
}
};
};
const { connect } = ReactRedux;
const VisibleTodoList = connect(
mapStateToProps,
mapDispatchToProps
)(TodoList);
Provider
これが
const { createStore } = Redux;
class Provider extends Component {
getChildContext () {
return {
store: this.props.store
}
render () {
return this.props.children
}
}
Provider.childContextTypes = {
store: React.PropTypes.object
}
ReactDOM.render(
<Provider
store={createStore(todoApp)}
>
<TodoApp />
</Provider>,
document.getElementById('app')
);
こうなる
const { Provider } = ReactRedux;
const { createStore } = Redux;
ReactDOM.render(
<Provider
store={createStore(todoApp)}
>
<TodoApp />
</Provider>,
document.getElementById('app')
);
何がどうなったか
Reduxのルールに則って、コンポーネントを作るときに書かなくてはならないボイラープレートが減った。
1. ライフサイクルメソッドがなくなる
コンテナコンポーネント(この例ではVisibleTodoList
)をルートとして、store
の更新のたびにrender
処理を発火させたい。そのため、コンポネーントをマウントしたタイミングでstore.subscribe()
でコールバック関数を登録し、アンマウント時にはstore.unsbscribe()
する必要があったがそれがなくなった。
2. 暗黙的なstore
の引き渡しのための記述がなくなる
プレゼンテーショナルコンポーネントにProps
を延々引き渡すのは野暮ったいので、Context
を使って暗黙的に引き渡すようにしたい。そのためには、store
をthis.context
から取得することと、そのコンポーネントのcontextTypes
を設定する必要があったがそれを意識しなくなった。また、Props
を渡す親のコンポーネントに対する記述(この例では<Provider>
)はごそっと実装しなくて良くなった。
終わりに
Reactを使うときに何が何でもこのAPIを使う必要はない。ただコンテナコンポーネントを作るときに必ず書くことになるコード片の総量が減り、より本質的な部分だけに集中できるようになる。