Reactの新Context APIとRedux is deadはどう関係するのか?
先日、reduxのメンテナであるMark EriksonさんがBlogged Answers: Redux — Not Dead Yet! という記事を書いていて「はーなんだろうなー」と流し読みしていた。
そんな折、React 16.3 がリリースされ、Context APIが刷新されたのを見て、「あ、これは確かに向き合い方ちょっと変わるかも」というのを思ったのでまとめてみる。
Redux — Not Dead Yet!を要約する
元記事をざっくり要約してみるとこんな感じ
- Reduxはどこにも行かないよ。メンテしていくし、役割もあるよ
- Context APIによってReduxを置き換えられるパターンはありえるよ。ただその場合、最初からReduxいらなかった可能性あるよ
- GraphQLがReduxを置き換えることはあるかも。でもReduxのほうがハマるパターンもあるよ
- 最近Dan Abramovさんが非同期レンダリングに関して発表したところ、ソーシャルメディアから「Reduxを置き換えるライブラリを発表した」みたいな広まりをしたけど、ミスリーディングで完全な間違いだよ
- React-Reduxは関心どころがあり、新ContextAPIを利用するようなPRを出したりReactの非同期レンダリングの問題を解決してるところだよ。
GraphQLとかの話も言及されてるけど、今回はContextに絞って話を進めてみる。
Context API
今までのContext APIはどんなもの?
今までReactは親から子への伝播をpropsを介して行い、親->子->孫で親の持つ値を孫に渡すには子をバケツリレー的に経由させなければならず煩雑だった。
これを解決するものとして今までもContextという機能はあった。
ただこれは実験的なAPIであり、一般的なアプリケーションには必要なく、状態管理のためには使うべきでない(そういう場合はReduxやMobXを使うべき)ということが書いてあった。
対して、新Context APIは?
今回、新APIは上記の実験的という文脈は取り払われている。
Context provides a way to pass data through the component tree without having to pass props down manually at every…reactjs.org
サンプルとして、カラースキームのThemeのようなものを題材として上げられている。(書きながら気づいたが、新しいContex APIの話には特にReduxとかMobXとかの文脈も取り払われているようだ。)
サンプルを拝借してみると、確かにこれは簡素になっているなーと感じる。ちょっと読み解いてみるとこんな具合。
今までであれば <Toolbar theme={theme} user={signedInUser} />
みたいな具合で値を渡したり、Reduxのグローバルな値として持たせなきゃいけなかったのがContextで解決できるようになっているのがわかる。
action的な関数を渡すパターン
ちょっとだけここで疑問になったのが、「functionを渡したり出来るの?」というところだったが、これもカウンターのサンプルで試してみたところ問題無かった。
書いてみて思ったが、ContextのConsumer側は同一のコンポーネントである場合とかだと、かなり扱いやすいんじゃないだろうか。
モーダル系とかだとかなり活きるところありそう。
今後Context / Reduxとそれぞれどう向き合っていくか?(主観)
- Reduxをもう今後使わないか?というと多分普通に使うことはあるだろうと思う
- 片一方、小規模だけどギリバケツリレーが辛いぐらいな規模のときは、Redux選んでいたのをContextで済ます、みたいなパターンも出てきそう
- 今までだと、 規模の大きさに準じて、State / Propsのみ -> オレオレFluxとかちっちゃめのやつ -> Reduxって順序で選定していたのが、State / Propsのみ -> Context / State / Props利用 -> Redux -> Redux / Context併用 って順序になっていく感じ?
- Context APIはネストされたバケツリレーを解決するものの、Stateの分割統治でとかdispatchとかreduxの持っていたバケツリレー以外の機能は、おそらくContextだけだと解決しづらい。
- ↑めちゃくちゃデカイstateと大量のmutation関数をContextに押し込めて運用するのとか地獄が見えそう
- ReduxとContextを併用する場合で言うと、「これReduxにいちいち入れるほどじゃないんだけどReduxに入れとかないと色んな所で参照できないから仕方なくReduxにぶっこんどかないといけないんだよなー」みたいなものがContextに切り出せそうな気がする
- ↑とはいえ、これはこれでReduxのSingle source of truthから外れるので、注意深く切り出す必要はある。
- このへんの併用の温度感としては、Redux使ってても全体に伝播させる必要が全くないような値についてComponentのLocal Stateを扱ってたのと同じ感じ。
Local StateについてはReduxのFAQでも言及されてる。僕がざっくり翻訳したやつもリンクしておく