Help us understand the problem. What is going on with this article?

シンプルなreact-reduxのconnectの書き方

More than 1 year has passed since last update.

react-reduxのconnect関数は、いろいろな書き方ができることで知られています。
(参考:ReactとReduxを結ぶパッケージ「react-redux」についてconnectの実装パターンを試す)

その柔軟さゆえ、実際にアプリケーションの中で書く場合にどのパターンを選ぶか悩むことが多いのではないでしょうか。今回は自分の気に入っている書き方を紹介します。

最もシンプルな書き方

import { connect } from 'react-redux'
import MyComponent from './my-component'
import { actionCreatorA, actionCreatorB } from './my-module'

export default connect(
  ({users, todos}) => ({users, todos}),
  {
    actionCreatorA,
    actionCreatorB
  }
)(MyComponent)

これだけです。stateを特にいじらずにconnectしたいときはこれで十分です。action creatorsは、rest spread operatorでまるっと渡してしまっても良いです。

reselectとか使うなら

import { connect } from 'react-redux'
import MyComponent from './my-component'
import { actionCreatorA, actionCreatorB } from './my-module'
import { mySelector } from './selectors'

export default connect(
  state => ({
    todos: mySelector(state)
  }),
  {
    actionCreatorA,
    actionCreatorB
  }
)(MyComponent)

reselectを使ったり、stateのconnectの仕方に工夫がいる場合はこのように書きます。

actionCreatorsをactionsでまとめたい時

import { connect } from 'react-redux'
import MyComponent from './my-component'
import { actionCreatorA, actionCreatorB } from './my-module'

export default connect(
  ({users, todos}) => ({users, todos}),
  dispatch => ({
    actions: {
      actionCreatorA: () => dispatch(actionCreatorA()),
      actionCreatorB: () => dispatch(actionCreatorB())
    }
  })
)(MyComponent)

よくある書き方と比べると

import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import MyComponent from './my-component'
import { actionCreatorA, actionCreatorB } from './my-module'

function mapStateToProps(state) {
  return { 
    users: state.users 
    todos: state.todos
  }
}

function mapDispatchToProps(dispatch) {
  return { actions: bindActionCreators(actionCreators, dispatch) }
}

export default connect(mapStateToProps, mapDispatchToProps)(MyComponent)

やっていることは紹介したシンプルな書き方と同じことですが、かなり冗長に見えます。

解説

キモは、mapStateToProps、mapDispatchToPropsを定義していないところです。特に再利用するものでもないですし、直接書いたほうが読みやすいと思います。

mapSteteToProps

connectの第一引数、即ちmapStateToPropsは、stateを引数に取り、Objectを返すただの関数です。
これは、stateをDestructuringしてアロー関数にしてconnectに直接渡してあげればシンプルに書けるということですね。

mapDispatchToProps

これはややこしいです。そもそも bindActionCreatorsはどこに行ったのでしょうか。
bindActionCreators の役割は、Store#dispatchで関数をラップすることです。簡易的に書くと、以下のようなobjectを返してくれます。

{
  actionCreatorA: () => {
    dispatch(actionCreatorA())
  },
  actionCreatorB: (foo) => {
    dispatch(actionCreatorB(foo))
  }
}

こうすることで、Store#dispatchを書かずに直接呼び出せるということです。

実はconnect関数も同じことをやってくれます。 正確に言うと、connect関数の第2引数は関数かobjectを取ることができて、オブジェクトが渡された場合はbindActionCreatorsと同じように、object内の各関数をdispatchでラップしてくれます。

この特性を利用すると、紹介したような書き方が実現できます。

export default connect(
  state => ({
    todos: mySelector(state)
  }),
  {
    actionCreatorA,  // dipatchでラップされる
    actionCreatorB  // dispatchでラップされる
  }
)(MyComponent)

以上です。
おかしなところがあればご指摘いただければと思いますmm

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away