Slide 1

Slide 1 text

unstated-next による
 Redux に頼らない状態管理の考察 React.kyoto v0.3.0 | Jul 19, 2019

Slide 2

Slide 2 text

神保 嘉秀 @jmblog じんぼ よしひで

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

今⽇話すこと • unstated-next の紹介 • 気になる点や個⼈的な所感

Slide 5

Slide 5 text

unstated-next の紹介

Slide 6

Slide 6 text

https://github.com/jamiebuilds/unstated-next unstated-next

Slide 7

Slide 7 text

Hooks の登場によって、 Redux などの「状態管理ライブラリ」に頼らず、 React の Context と Hooks だけで状態管理を実装することが 可能になった。
 
 unstated-next はその実装をサポートしてくれる、
 必要最⼩限なライブラリ(わずか 200バイト)

Slide 8

Slide 8 text

unstated-next と unstated の関係 • unstated というライブラリもあってちょっとややこしい。 • 開発者はどちらも @jamiebuilds ⽒。 • unstated は Context を活⽤したシンプルな状態管理ライブラリ。
 2018年前半に発表された。 • その後、React から Hooks がリリースされ、unstated のコンセプトをよりコン パクトに実現できるようになったため、Hooks ベースの API に⼀新して unstated-next という別パッケージで 2019年5⽉にリリースされた。

Slide 9

Slide 9 text

まず、 Context と Hooks だけで状態管理を実装すると こんなコードになる

Slide 10

Slide 10 text

useState() あるいは useReducer() を使い、 state とその更新 ロジックを内部に保持したカスタム Hook を⽤意する。

Slide 11

Slide 11 text

このカスタムHook をコンポーネントで直接利⽤すると、Hook 内の state は コンポーネントごとのローカル state となるが、Context で管理することで、 同じ state の値を複数のコンポーネントで利⽤できるようになる。

Slide 12

Slide 12 text

にカスタムHookの中⾝を渡す。 これにより、Contextの中⾝ = state が更新されると、 コンポーネントが変更を検知して、再描画するようになる。

Slide 13

Slide 13 text

コンポーネントでは useContext() を使って、
 Context の中⾝ = state を取得し利⽤することができる。

Slide 14

Slide 14 text

これだけで⼗分機能する。

Slide 15

Slide 15 text

state logics こういうイメージ Context custom hook

Slide 16

Slide 16 text

Context を Container(容器、⼊れ物)と呼ぶと、 よりイメージしやすくなる。 Container state logics custom hook

Slide 17

Slide 17 text

さっきのコードを unstated-next を使って 書き換えてみると、こうなる。

Slide 18

Slide 18 text

createContainer(customHook) で Container を作成し、 カスタムHookを格納する。

Slide 19

Slide 19 text

Container は Context と同様、Provider を持つ。

Slide 20

Slide 20 text

コンポーネントでは useContainer() を使って、
 Container の中⾝ = state を取得し利⽤することができる。

Slide 21

Slide 21 text

これだけ。

Slide 22

Slide 22 text

unstated-next を使わなくても⼗分シンプルだが、 unstated-next による「Container」という概念を使うことで よりわかりやすくなる。

Slide 23

Slide 23 text

Redux よりも優れている点 • ファイルサイズは 1/40 • 学習コストが圧倒的に低い(Context と Hooks さえ知っていればいい) • ほぼ素の React なので、どんなライブラリとも連携しやすい • パフォーマンスの⾯でも有利

Slide 24

Slide 24 text

Redux よりも優れている点 • ファイルサイズは 1/40 • 学習コストが圧倒的に低い(Context と Hooks さえ知っていればいい) • ほぼ素の React なので、どんなライブラリとも連携しやすい • パフォーマンスの⾯でも有利 ← どういうことか?

Slide 25

Slide 25 text

Redux Store container component container component container component container component Redux では、State が更新されると、マウント中の すべての Container Component(Store とつながっているコンポーネント)が、変更の通知を受けとって、 mapStateToProps(ある いは useSelector) を実⾏する mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()

Slide 26

Slide 26 text

Redux Store container component container component container component container component 処理の遅い mapState が1つ存在していると、state が変更されるたびに毎回実⾏されるため、 アプリケーション全体のパフォーマンスを落とす重⼤なボトルネックとなる。 mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()

Slide 27

Slide 27 text

Redux Store container component container component container component container component 「⽬に⾒えて遅くはないが、微妙に遅い」という mapState でも、たくさん存在すると、 やはりパフォーマンス劣化の要因となってくる。 mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()

Slide 28

Slide 28 text

reselect によるメモ化など、 回避するためのベストプラクティスは存在するが、 そもそも、グローバルな単⼀の Store に すべてのコンポーネントが依存している という構造が引き起こす問題。

Slide 29

Slide 29 text

component component component component component container container container container 次のように、Container (≒ Store) を複数に分けて、コンポーネントが本当に必要としている 場合だけ共有するようになっていれば、この問題は避けられる。

Slide 30

Slide 30 text

component component component component component container container container container もしパフォーマンス上問題のあるコンポーネントが存在していても、⾃分に関係のない state が 変更されたときは何も起こらないので、コンポーネントが与える影響範囲は限定される。

Slide 31

Slide 31 text

unstated-next では、
 Redux のようにアプリケーション全体の State を ⼀つの巨⼤な Container で管理するのではなく、 適切な粒度に分割して管理することが推奨されている。 ただし、Container の粒度に関する制約やルールは
 存在していないので、⾃分でルールを決めて運⽤する必要がある。

Slide 32

Slide 32 text

気になる点や個⼈的な所感

Slide 33

Slide 33 text

Container の最適な粒度は? • ⼩さすぎると管理が煩雑になりそうだし、⼤きすぎると Redux が抱える のと同じ問題を引き起こす危険性が増す。 • まずは、ある程度の機能ごとに分割してみて、少しづつ調整していく感じ になりそう。

Slide 34

Slide 34 text

Container の最適な粒度は? • 正規化(normalize)されたデータは判断しやすい。
 例えば、製品データ を「byId」と「visibleIds」に正規化したとすると、 それぞれを Container にすれば、 と で必 要とする State が良い感じに分離できる。

Slide 35

Slide 35 text

Redux で Store を複数に分割すればいいのでは? • Redux の FAQ に回答が載っている。
 可能は可能だけど、Redux DevTools とか使えなくなるし、単⼀の Store で使ってもらうことを想定している、とのこと。
 
 https://redux.js.org/faq/store-setup#can-or-should-i-create-multiple- stores-can-i-import-my-store-directly-and-use-it-in-components- myself

Slide 36

Slide 36 text

「Provider ⼊れ⼦地獄」にならないか? • 多くの Container を必要するコンポーネントでは の⼊れ⼦がかなり深くなる。
 


Slide 37

Slide 37 text

「Provider ⼊れ⼦地獄」にならないか? • helper 関数を⽤意するぐらいしか回避策はなさそう。
 https://github.com/jamiebuilds/unstated-next/issues/ 35#issuecomment-500255562 • ⼊れ⼦があまりにも深い場合は、Container の粒度が細かすぎるか、コン ポーネントの責務が⼤きすぎる可能性が考えられるので、
 リファクタリングのポイントといえるかも。

Slide 38

Slide 38 text

最適化のコツは? • Redux での「reselectを使いましょう」的な、unstated-next ならではの 最適化テクニックは特にない。 • 素の React とほぼ同じなので、React のスタンダードな最適化がそのまま 使える。
 https://github.com/jamiebuilds/unstated-next#tip-3-optimizing- components

Slide 39

Slide 39 text

デバッグはどうする? • 専⽤のデバッグツールはない。 • React Developer Tools に Hooks のサポートが⼊っていて、最新の state の値は確認できるが、変更履歴などは確認できない。
 https://github.com/facebook/react-devtools/pull/1272 • これが⼀番つらいところかも。

Slide 40

Slide 40 text

今すぐ Redux を捨てて unstated-next に乗り換えるべきか? • Redux よりも簡単にコーディングできるのは間違いないが、Redux とは 別の全体設計⼒が試される。 • 既存のアプリケーションに導⼊するのであれば、パフォーマンスチューニ ングの⼀環として、書き換えが頻発する State の⼀部を unstated-next に 置き換えてみるのはありだと思う。

Slide 41

Slide 41 text

スケールするのか?(⼤規模アプリでも使えるか?) • Redux を使って安定した⼤規模アプリケーションを実装できる⼒量があれ ば、unstated-next を使ってもうまくいくのではないか。 • 個⼈的には、最適なアプリケーションのアーキテクチャを探っていきた い。

Slide 42

Slide 42 text

スケールするのか?(⼤規模アプリでも使えるか?) • Container はクリーンアーキテクチャの Presenter(ユースケースやエンティティのデータ 形式を変換して、外界である UI に伝える役割)に あたるように思うが、React にがっつり依存して いるのでこのレイヤーなのか少しモヤモヤする。 • クリーンアーキテクチャに適⽤するなら unstated-next ではなく unstated のほうが
 ぴったりはまりそうな印象。

Slide 43

Slide 43 text

もし実戦投⼊してノウハウが溜まったら、ぜひシェアしてください!

Slide 44

Slide 44 text

おわり