ReactReduxの役割を整理

  • 11
    いいね
  • 0
    コメント

はじめに

こちらに記載があるように、

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にバインドさせるためのライブラリがある。そしてこのライブラリは、connectProviderというAPIを提供している。

ReactReduxの使用前後のコードを比較する

まずは、使用前後のコードを並べる。

connect

これが

ReactReduxを使わずにコンテナコンポーネントを作る
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
}

こうなる

ReactReduxを使ってコンテナコンポーネントを作る
/*
 *  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を使って暗黙的に引き渡すようにしたい。そのためには、storethis.contextから取得することと、そのコンポーネントのcontextTypesを設定する必要があったがそれを意識しなくなった。また、Propsを渡す親のコンポーネントに対する記述(この例では<Provider>)はごそっと実装しなくて良くなった。

終わりに

Reactを使うときに何が何でもこのAPIを使う必要はない。ただコンテナコンポーネントを作るときに必ず書くことになるコード片の総量が減り、より本質的な部分だけに集中できるようになる。