react-reduxのconnect()を図解する
ReactとReduxの勉強中です。react-reduxのconnect()の理解に時間がかかったので、同じように悩んでいる方に向けて図にして説明します。初心者向けの説明なので、正確さよりもわかりやすさを重視しています。
目次
Reduxの世界
まずはReduxの世界です。シーケンス図にするとこんな感じです。
- viewはユーザの動作(クリックなど)が発生したら、actionを作成してstoreに渡す(dispatchする)。
- storeは状態(state)を保持している。dispatchが呼ばれると、storeはactionとstateをreducerに渡す。
- reducerはactionとstateを受け取り、新たなstateを作成して返す。
- stateが更新されるとviewに通知され、再描画される
Reactの世界
Reactの世界をツリーで表すとこんな感じです。
- ツリーの各ノードをコンポーネント(component)と呼ぶ。
- 各コンポーネントは状態(state)を持っている。
- 各コンポーネントは自身のstateのみを更新することができる。
- stateが更新されると自動的に再描画される。
- 親から子に値(props)を渡すことができる。
- 親から子に渡す値には、関数も含まれる。
- 親は子の状態を直接(例えば、childComponentA.state.isActiveのように)参照することはできない。
- 子コンポーネントが親から渡された関数を呼び出すことによって、子の状態を親に伝えることができる。
ここで、親から子に渡される値(props)をざっくり分けると、以下の2種類になります。
データ型 | 用途 |
---|---|
数値、文字列、真偽値、配列、もしくはそれらで構成されているオブジェクト | 表示のために使用される |
関数 | 子コンポーネントのイベントを親コンポーネントに通知するために使用される |
React-reduxの世界
Reduxでは、状態(state)は基本的にstoreが持ちます。そして、react-reduxの世界でも、stateはstoreが管理し、各コンポーネントはstateを(ほとんど)持ちません。
何もしない状態だと、reactとreduxの世界は分断されています。
Reactの各コンポーネントは、
- 表示のための値
- stateを書き換える関数(dispatch)
が欲しいのですが、このままではstoreと分断されているために値の取得と変更が行えません。
そこで、connect()の登場です。connectはReactコンポーネントとstoreをつないでくれます。
ここでは、ParentComponentとChildComponentの間に、connect()を行うContainerInMiddleを入れます。ContainerInMiddleはstoreからstateとdispatchを受け取って、子コンポーネントに必要な値を渡します。
connect()の引数
connect()の呼び出し方は以下のようになっていて、mapStateToPropsとmapDispatchToPropsという2つの関数を引数に取ります。
const ContainerInMiddle = connect(
mapStateToProps,
mapDispatchToProps
)(ChildComponent)
それぞれ以下の役割があります。
データ型 | 用途 |
---|---|
mapStateToProps | storeが持っているstateをpropsに入れて子コンポーネントに渡す |
mapDispatchToProps | dispatchを呼び出す関数をpropsに入れて子コンポーネントに渡す |
ざっくりいうと、mapStateToPropsでは、描画のための値をstoreから持ってくる役割があって、mapDispatchToPropsは、”ユーザの動作があった時の関数”を渡す役割があります。
mapStateToPropsの実装は以下のようになります。
const mapStateToProps = state => ({ todos: state.todos })
state.todo
の内容を、todo
という名前で子コンポーネントに渡すよ、という意味です。このように書いておくと、子コンポーネント(上記の例ではChildComponent)でprops.todo
で値が取得できるようになります。
mapDispatchToPropsの実装は以下のようになります。
const mapDispatchToProps = dispatch => ({ handleClick: id => dispatch(someAction(id)) })
id => dispatch(someAction(id))
という関数を、handleClick
という名前で子コンポーネントに渡すよ、という意味です。このように書いておくと、子コンポーネント(上記の例ではChildComponent)でprops.handleClickで値が取得できるようになります。
まとめ
connect()でstoreとcomponentをつなぐイメージを文中で示しました。
react-reduxのconnect()は、stateとdispatch関数をpropsに入れて子コンポーネントに渡すという動作をします。これによって、stateの情報を取得したり書き換えたりできます。また、子コンポーネント側では、reduxを意識することなく実装ができます。
あとがき
coonect()の書き方は、理解できれば簡単ですが、記号がいっぱいの書き方なので、初めはとまどいました。慣れれば簡単なので、文中の図が理解の助けになれば幸いです。
シーケンス図はこちらを利用して作成しました。とても便利です。