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
Duckdb-Wasmでローカルダッシュボードを作ってみた
nkforwork
0
120
.NET のための通信フレームワーク MagicOnion 入門 / Introduction to MagicOnion
mayuki
1
1.4k
初めてDefinitelyTypedにPRを出した話
syumai
0
400
Hotwire or React? ~アフタートーク・本編に含めなかった話~ / Hotwire or React? after talk
harunatsujita
1
120
アジャイルを支えるテストアーキテクチャ設計/Test Architecting for Agile
goyoki
9
3.3k
TypeScript Graph でコードレビューの心理的障壁を乗り越える
ysk8hori
2
1.1k
詳細解説! ArrayListの仕組みと実装
yujisoftware
0
580
Amazon Bedrock Agentsを用いてアプリ開発してみた!
har1101
0
330
どうして僕の作ったクラスが手続き型と言われなきゃいけないんですか
akikogoto
1
120
TypeScriptでライブラリとの依存を限定的にする方法
tutinoko
2
660
【Kaigi on Rails 2024】YOUTRUST スポンサーLT
krpk1900
1
330
macOS でできる リアルタイム動画像処理
biacco42
9
2.4k
Featured
See All Featured
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
47
2.1k
Thoughts on Productivity
jonyablonski
67
4.3k
How to Ace a Technical Interview
jacobian
276
23k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.8k
Building a Scalable Design System with Sketch
lauravandoore
459
33k
Why Our Code Smells
bkeepers
PRO
334
57k
Keith and Marios Guide to Fast Websites
keithpitt
409
22k
4 Signs Your Business is Dying
shpigford
180
21k
Six Lessons from altMBA
skipperchong
27
3.5k
Speed Design
sergeychernyshev
24
610
Raft: Consensus for Rubyists
vanstee
136
6.6k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
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 のほうが ぴったりはまりそうな印象。
もし実戦投⼊してノウハウが溜まったら、ぜひシェアしてください!
おわり