Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
unstated-next による Redux に頼らない状態管理の考察
Search
Yoshihide Jimbo
July 19, 2019
Programming
9
5.1k
unstated-next による Redux に頼らない状態管理の考察
React.kyoto v0.3.0 でのLT発表資料です。
https://react-kyoto.connpass.com/event/137847/
Yoshihide Jimbo
July 19, 2019
Tweet
Share
More Decks by Yoshihide Jimbo
See All by Yoshihide Jimbo
高齢者でも使えるプロダクトUIの挑戦 / Designing User Interfaces for the Elderly
jmblog
32
27k
雰囲気でやってる人向けの Redux 再入門
jmblog
21
6.2k
わかりやすいグラフを作ろう
jmblog
3
1.3k
Web Components で 社内 UI ライブラリを作っている話
jmblog
11
4k
gulp: The Good Parts
jmblog
29
5.8k
CSS in JS と CSS Modules
jmblog
25
4.6k
PostCSS とは何か
jmblog
38
9.6k
Kaizen Platform における UI ライブラリのワークフロー
jmblog
30
6k
フロントエンドエンジニアのための Dotfiles
jmblog
53
8.4k
Other Decks in Programming
See All in Programming
macOS でできる リアルタイム動画像処理
biacco42
9
2.4k
TypeScriptでライブラリとの依存を限定的にする方法
tutinoko
2
670
聞き手から登壇者へ: RubyKaigi2024 LTでの初挑戦が 教えてくれた、可能性の星
mikik0
1
130
Pinia Colada が実現するスマートな非同期処理
naokihaba
4
230
Generative AI Use Cases JP (略称:GenU)奮闘記
hideg
1
290
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
330
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
1
100
Figma Dev Modeで変わる!Flutterの開発体験
watanave
0
130
Macとオーディオ再生 2024/11/02
yusukeito
0
370
GitHub Actionsのキャッシュと手を挙げることの大切さとそれに必要なこと
satoshi256kbyte
5
430
Contemporary Test Cases
maaretp
0
140
3 Effective Rules for Using Signals in Angular
manfredsteyer
PRO
0
110
Featured
See All Featured
A Tale of Four Properties
chriscoyier
156
23k
Imperfection Machines: The Place of Print at Facebook
scottboms
265
13k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
126
18k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
28
2k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
VelocityConf: Rendering Performance Case Studies
addyosmani
325
24k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
226
22k
How GitHub (no longer) Works
holman
310
140k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
665
120k
For a Future-Friendly Web
brad_frost
175
9.4k
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
16
2.1k
How to train your dragon (web standard)
notwaldorf
88
5.7k
Transcript
unstated-next による Redux に頼らない状態管理の考察 React.kyoto v0.3.0 | Jul 19, 2019
神保 嘉秀 @jmblog じんぼ よしひで
None
今⽇話すこと • unstated-next の紹介 • 気になる点や個⼈的な所感
unstated-next の紹介
https://github.com/jamiebuilds/unstated-next unstated-next
Hooks の登場によって、 Redux などの「状態管理ライブラリ」に頼らず、 React の Context と Hooks だけで状態管理を実装することが
可能になった。 unstated-next はその実装をサポートしてくれる、 必要最⼩限なライブラリ(わずか 200バイト)
unstated-next と unstated の関係 • unstated というライブラリもあってちょっとややこしい。 • 開発者はどちらも @jamiebuilds
⽒。 • unstated は Context を活⽤したシンプルな状態管理ライブラリ。 2018年前半に発表された。 • その後、React から Hooks がリリースされ、unstated のコンセプトをよりコン パクトに実現できるようになったため、Hooks ベースの API に⼀新して unstated-next という別パッケージで 2019年5⽉にリリースされた。
まず、 Context と Hooks だけで状態管理を実装すると こんなコードになる
useState() あるいは useReducer() を使い、 state とその更新 ロジックを内部に保持したカスタム Hook を⽤意する。
このカスタムHook をコンポーネントで直接利⽤すると、Hook 内の state は コンポーネントごとのローカル state となるが、Context で管理することで、 同じ
state の値を複数のコンポーネントで利⽤できるようになる。
<Context.Provider> にカスタムHookの中⾝を渡す。 これにより、Contextの中⾝ = state が更新されると、 コンポーネントが変更を検知して、再描画するようになる。
コンポーネントでは useContext() を使って、 Context の中⾝ = state を取得し利⽤することができる。
これだけで⼗分機能する。
state logics こういうイメージ Context custom hook
Context を Container(容器、⼊れ物)と呼ぶと、 よりイメージしやすくなる。 Container state logics custom hook
さっきのコードを unstated-next を使って 書き換えてみると、こうなる。
createContainer(customHook) で Container を作成し、 カスタムHookを格納する。
Container は Context と同様、Provider を持つ。
コンポーネントでは useContainer() を使って、 Container の中⾝ = state を取得し利⽤することができる。
これだけ。
unstated-next を使わなくても⼗分シンプルだが、 unstated-next による「Container」という概念を使うことで よりわかりやすくなる。
Redux よりも優れている点 • ファイルサイズは 1/40 • 学習コストが圧倒的に低い(Context と Hooks さえ知っていればいい)
• ほぼ素の React なので、どんなライブラリとも連携しやすい • パフォーマンスの⾯でも有利
Redux よりも優れている点 • ファイルサイズは 1/40 • 学習コストが圧倒的に低い(Context と Hooks さえ知っていればいい)
• ほぼ素の React なので、どんなライブラリとも連携しやすい • パフォーマンスの⾯でも有利 ← どういうことか?
Redux Store container component container component container component container component
Redux では、State が更新されると、マウント中の すべての Container Component(Store とつながっているコンポーネント)が、変更の通知を受けとって、 mapStateToProps(ある いは useSelector) を実⾏する mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()
Redux Store container component container component container component container component
処理の遅い mapState が1つ存在していると、state が変更されるたびに毎回実⾏されるため、 アプリケーション全体のパフォーマンスを落とす重⼤なボトルネックとなる。 mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()
Redux Store container component container component container component container component
「⽬に⾒えて遅くはないが、微妙に遅い」という mapState でも、たくさん存在すると、 やはりパフォーマンス劣化の要因となってくる。 mapStateToProps() mapStateToProps() mapStateToProps() mapStateToProps()
reselect によるメモ化など、 回避するためのベストプラクティスは存在するが、 そもそも、グローバルな単⼀の Store に すべてのコンポーネントが依存している という構造が引き起こす問題。
component component component component component container container container container 次のように、Container
(≒ Store) を複数に分けて、コンポーネントが本当に必要としている 場合だけ共有するようになっていれば、この問題は避けられる。
component component component component component container container container container もしパフォーマンス上問題のあるコンポーネントが存在していても、⾃分に関係のない
state が 変更されたときは何も起こらないので、コンポーネントが与える影響範囲は限定される。
unstated-next では、 Redux のようにアプリケーション全体の State を ⼀つの巨⼤な Container で管理するのではなく、 適切な粒度に分割して管理することが推奨されている。
ただし、Container の粒度に関する制約やルールは 存在していないので、⾃分でルールを決めて運⽤する必要がある。
気になる点や個⼈的な所感
Container の最適な粒度は? • ⼩さすぎると管理が煩雑になりそうだし、⼤きすぎると Redux が抱える のと同じ問題を引き起こす危険性が増す。 • まずは、ある程度の機能ごとに分割してみて、少しづつ調整していく感じ になりそう。
Container の最適な粒度は? • 正規化(normalize)されたデータは判断しやすい。 例えば、製品データ を「byId」と「visibleIds」に正規化したとすると、 それぞれを Container にすれば、<ProductList> と
<ProductDetail> で必 要とする State が良い感じに分離できる。
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
「Provider ⼊れ⼦地獄」にならないか? • 多くの Container を必要するコンポーネントでは <Container.Provider> の⼊れ⼦がかなり深くなる。
「Provider ⼊れ⼦地獄」にならないか? • helper 関数を⽤意するぐらいしか回避策はなさそう。 https://github.com/jamiebuilds/unstated-next/issues/ 35#issuecomment-500255562 • ⼊れ⼦があまりにも深い場合は、Container の粒度が細かすぎるか、コン
ポーネントの責務が⼤きすぎる可能性が考えられるので、 リファクタリングのポイントといえるかも。
最適化のコツは? • Redux での「reselectを使いましょう」的な、unstated-next ならではの 最適化テクニックは特にない。 • 素の React とほぼ同じなので、React
のスタンダードな最適化がそのまま 使える。 https://github.com/jamiebuilds/unstated-next#tip-3-optimizing- components
デバッグはどうする? • 専⽤のデバッグツールはない。 • React Developer Tools に Hooks のサポートが⼊っていて、最新の
state の値は確認できるが、変更履歴などは確認できない。 https://github.com/facebook/react-devtools/pull/1272 • これが⼀番つらいところかも。
今すぐ Redux を捨てて unstated-next に乗り換えるべきか? • Redux よりも簡単にコーディングできるのは間違いないが、Redux とは 別の全体設計⼒が試される。
• 既存のアプリケーションに導⼊するのであれば、パフォーマンスチューニ ングの⼀環として、書き換えが頻発する State の⼀部を unstated-next に 置き換えてみるのはありだと思う。
スケールするのか?(⼤規模アプリでも使えるか?) • Redux を使って安定した⼤規模アプリケーションを実装できる⼒量があれ ば、unstated-next を使ってもうまくいくのではないか。 • 個⼈的には、最適なアプリケーションのアーキテクチャを探っていきた い。
スケールするのか?(⼤規模アプリでも使えるか?) • Container はクリーンアーキテクチャの Presenter(ユースケースやエンティティのデータ 形式を変換して、外界である UI に伝える役割)に あたるように思うが、React にがっつり依存して
いるのでこのレイヤーなのか少しモヤモヤする。 • クリーンアーキテクチャに適⽤するなら unstated-next ではなく unstated のほうが ぴったりはまりそうな印象。
もし実戦投⼊してノウハウが溜まったら、ぜひシェアしてください!
おわり