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
React Hook Form はどのように再レンダリングを最適化しているのか?
Search
Kotaro Sugawara
October 29, 2021
Technology
9
5.8k
React Hook Form はどのように再レンダリングを最適化しているのか?
【READYFOR×コミューン】業務に活かせるReact LT & 座談会
https://readyfor.connpass.com/event/224586/
Kotaro Sugawara
October 29, 2021
Tweet
Share
More Decks by Kotaro Sugawara
See All by Kotaro Sugawara
OpenAPI Generator と TypeScript による型安全なスキーマ駆動開発
kotarella1110
4
44k
Other Decks in Technology
See All in Technology
[I/O Extended Android 2024] What`s new in Android 2024
kyeongwan
0
220
[NIKKEI Tech Talk]Bias for Action!! 実践から学ぶための仕組とコミュニティ / Community for Practice and Learning
kanamasa
0
260
Flutter研修【MIXI 24新卒技術研修】
mixi_engineers
PRO
0
160
20240725 LLMによるDXのビジョンと、今何からやるべきか @Azure OpenAI Service Dev Day
nrryuya
3
1.1k
コンテナ・K8s研修 - 後半 Kubernetes 基礎&ハンズオン【MIXI 24新卒技術研修】
mixi_engineers
PRO
1
120
JBUG岡山 #6 WordCamp男木島の チームビルディング
takeshifurusato
0
150
Git 研修 Basic【MIXI 24新卒技術研修】
mixi_engineers
PRO
0
310
DevIO2024_レガシー運用からの脱却 -クラウド活用の実践事例とベストプラクティス-
jun2882
0
210
テストケースの自動生成に生成AIの導入を試みた話と生成AIによる今後の期待
shift_evolve
0
180
GoとアクターモデルでES+CQRSを実践! / proto_actor_es_cqrs
ytake
1
150
データベース研修 分析向けSQL入門【MIXI 24新卒技術研修】
mixi_engineers
PRO
0
110
[NIKKEI Tech Talk] KDDI/KAG Scrum & Community for Engineering Training
curanosuke
2
220
Featured
See All Featured
Web Components: a chance to create the future
zenorocha
307
41k
Building an army of robots
kneath
301
42k
Bootstrapping a Software Product
garrettdimon
PRO
304
110k
A designer walks into a library…
pauljervisheath
201
24k
Debugging Ruby Performance
tmm1
71
11k
Gamification - CAS2011
davidbonilla
78
4.9k
Imperfection Machines: The Place of Print at Facebook
scottboms
262
13k
Keith and Marios Guide to Fast Websites
keithpitt
408
22k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
29
2.5k
Facilitating Awesome Meetings
lara
46
5.8k
A Tale of Four Properties
chriscoyier
155
22k
Mobile First: as difficult as doing things right
swwweet
219
8.8k
Transcript
1 React Hook Form はどのように再レンダリングを最適化しているのか? 2021/10/29 菅原 弘太郎
2 自己紹介 Kotaro Sugawara @kotarella1110 • エンジニアリング本部/システム基盤部 • フロントエンドエンジニア •
2020年11月入社(もう少しで入社して一年 🎉) • 岩手県在住のリモートワーカー • React Hook Form のメンバー #ReactLT
3 本日お話しすること • React Hook Form とは? • React のパフォーマンス最適化
• React Hook Form はどのように再レンダリングを最適化しているのか? #ReactLT
4 React Hook Form とは? #ReactLT
5 React Hook Form とは? 非制御コンポーネントをベースに構築されたフォームバリデーション用の React フックライブラリ #ReactLT
6 React Hook Form とは? React Hook Form のコード例 #ReactLT
7 React Hook Form とは? 特徴 • パフォーマンス、UX、DX を念頭に置いて構築 •
非制御フォームバリデーション • UI ライブラリと簡単に統合可能(Controlled Components もサポート) • パッケージのサイズが小さく、依存関係がない • HTML 標準のバリデーション(Constraint Validation API) • スキーマベースのバリデーションをサポート(Yup、Zod、Superstruct など) #ReactLT
8 React Hook Form とは? 特徴 • パフォーマンス、UX、DX を念頭に置いて構築 •
非制御フォームバリデーション • UI ライブラリと簡単に統合可能(Controlled Components もサポート) • パッケージのサイズが小さく、依存関係がない • HTML 標準のバリデーション(Constraint Validation API) • スキーマベースのバリデーションをサポート(Yup、Zod、Superstruct など) #ReactLT
9 React のパフォーマンス最適化 #ReactLT
10 React のパフォーマンス最適化 React のパフォーマンス最適化において重要なこと 無駄な計算と再レンダリングを抑える #ReactLT
11 React のパフォーマンス最適化 パフォーマンスの最適化手法 • useCallback/useMemo による関数と値のメモ化 ◦ 再レンダリング・値の不要な再計算をスキップ •
React.memo によるコンポーネントのメモ化 ◦ useCallback/useMemo と併用することで、コンポーネントの再レンダリングを スキップ • Context の使用 ◦ Provider と Consumer(Context から値を取得するコンポーネント)間の中間コ ンポーネントの再レンダリングをスキップ #ReactLT
12 React のパフォーマンス最適化 Context の分割について Provider 配下の全ての Consumer は、Provider の
value プロパティが変 更されるたびに再レンダリングが発生 します。 これは機能的に問題はありませんが、 不要な再レンダリングが発生してしまう ケースがあります。 Provider Consumer Consumer #ReactLT
13 Context の分割について React のパフォーマンス最適化 例えば右の図のように、状態(可変)と それを更新する関数(不変)を value に 渡しているケースです。ConsumerA
で は Context から state のみを取得し、 ConsumerB では setState のみを取 得します。 value={{ state, setState }} Provider ConsumerB ConsumerA state setState #ReactLT
14 Context の分割について React のパフォーマンス最適化 setState が呼び出される度に Provider では state
が更新され value プロパティに変更が発生します。 value={{ state, setState }} Provider ConsumerB ConsumerA state setState state setState(value) の呼び出し #ReactLT
15 Context の分割について React のパフォーマンス最適化 value プロパティに変更があるため、 state を Context
から取得している ConsumerA だけでなく ConsumerB も 再レンダリングが発生してしまいます。 value={{ state, setState }} Provider ConsumerB ConsumerA state setState state setState(value) の呼び出し #ReactLT
16 Context の分割について React のパフォーマンス最適化 この不要な再レンダリングを排除するため には Context を分割する必要があります。 右の図のように分割することで、
ProviderB の value プロパティは不変にな るため、ConsumerB は state が更新され ても再レンダリングが発生しなくなります。 value={{ setState }} ProviderB ConsumerB ConsumerA value={{ state }} state setState ProviderA setState(value) の呼び出し state #ReactLT
17 Context の分割について React のパフォーマンス最適化 とはいえ、Consumer 側で再レンダリングを細かく制御したい場合など Context を単純に分割できないケースがあります。 例えば、Redux
の useSelector のように、selector 関数が返す値に更新が あった場合のみ再レンダリングを行うといったことを Context のみで実現するこ とは難しいです。 #ReactLT
18 React Hook Form はどのように再レンダリングを最適化してるのか? #ReactLT
19 Subscription ベースの状態管理 #ReactLT
20 Subscription ベースの状態管理 Subscription ベースの状態管理を採用 • React Hook Form は再レンダリングを細かく制御するために
Redux や Recoil などと同じように Subscription ベースの状態管理を採用 • これにより、useWatch や useFormState フックはそれらを使用するコン ポーネントレベルで再レンダリングを分離することを可能にしている #ReactLT
21 Subscription ベースの状態管理 Subscription ベースの状態管理とは? • コンポーネントで値の変更をサブスクライブし、 受け取った値に応じて状態を更新する • Provider
での状態の更新を避けることができ、 サブスクライブしているコンポーネントでのみ再 レンダリングが発生する • 値に応じて細かい再レンダリングの制御が可能 Provider ConsumerB ConsumerA value state 値の変更通知 値の変更をサブスクライブ 受け取った値に応じて状態を更新 #ReactLT
22 Subscription ベースの状態管理 実現方法 • 値の変更を通知する仕組みと値の変更をサブ スクライブ(購読)して何かしら処理する仕組み さえあれば Subscription ベースの状態管理を
実現できる • React Hook Form ではその仕組みとして RxJS の Subject の簡易的な実装をしている • Subject は React Hook Form が提供する control オブジェクトに含まれる subject.subscribe(value => { setState(value) }) subject.next(value) value={{ subject }} Provider ConsumerB ConsumerA value subject subject state 値の変更通知 値の変更をサブスクライブ 受け取った値に応じて状態を更新 #ReactLT
23 Subscription ベースの状態管理 実装例 • Subscription ベースで状態を管理する useCountState フックの 実装例
◦ 修正前 ▪ https://codesandbox.io/s/subscription-based-usecountstate-before-9spnk ◦ 修正後 ▪ https://codesandbox.io/s/subscription-based-usecountstate-after-b4eef • React Hook Form の watch と useWatch の簡易的な実装例 ◦ https://codesandbox.io/s/react-hook-form-watch-usewatch-implementation-u1r si #ReactLT
24 コンポーネントで使用されている状態のみを更新 #ReactLT
25 コンポーネントで使用されている状態のみを更新 React Hook Form の formState について • React
Hook Form が提供する formState というオブジェクトは isDirty 、 isSubmitting、errors などのフォームに関する状態が含まれている • React Hook Form は formState の内、コンポーネントで使用されている状 態のみを更新して再レンダリングを発生させている #ReactLT
26 こちらは2文字以上入力するとバリデーションエラーが発生するフィールドの例です。 コンポーネントで使用されている状態のみを更新 コンポーネントで使用されている状態のみを更新するとは? #ReactLT
27 コンポーネントで使用されている状態のみを更新 コンポーネントで使用されている状態のみを更新するとは? formState の内 isDirty と errors を使用してログを出力してみます。 フィールドで2文字入力すると以下のような3行のログが出力されます。
合計3回レンダリングされています。 #ReactLT
28 コンポーネントで使用されている状態のみを更新 コンポーネントで使用されている状態のみを更新するとは? 続いて、formState の内 errors のみを使用するように修正してログを出力してみます。 同じように2文字入力すると、以下のような2行のログが出力されます。 合計3回のレンダリングから2回のレンダリングに減りました。 #ReactLT
29 コンポーネントで使用されている状態のみを更新 コンポーネントで使用されている状態のみを更新するとは? これは、コンポーネントで使用している errors のみ更新され、isDirty などの errors 以外の状 態は更新されないためです。
これにより不要な再レンダリングが排除されます。 #ReactLT
30 コンポーネントで使用されている状態のみを更新 実現方法 • Proxy や Object.defineProperty/Object.defineProperties を活用してコン ポーネントで使用されている状態のみを更新し、不要な再レンダリングを排 除することができる
• React Hook Form では Object.defineProperty の getter で状態が使用さ れているかを検知し、使用されている状態のみを更新するようにしている #ReactLT
31 コンポーネントで使用されている状態のみを更新 実装例 • コンポーネントで使用されている状態のみを更新する useAsyncフックの実 装例 ◦ 修正前 ▪
https://codesandbox.io/s/dependency-collection-useasync-before-5epsq ◦ 修正後 ▪ https://codesandbox.io/s/dependency-collection-useasync-after-30o24 #ReactLT
32 まとめ • React Hook Form においてパフォーマンスは重要であり、不要な再レンダ リングを排除することは主要な目標の一つ • React
は useCallback・useMemo・React.memo・Context の使用 ・Context の分割によりパフォーマンスを最適化することができる • React Hook Form はSubscription ベースの状態管理を採用し、コンポー ネントで使用されている状態のみを更新することにより再レンダリングを最 適化している #ReactLT
33 パフォーマンスのボトルネックが見つかった場合など、 本日紹介した再レンダリングの最適化を実践してみてください 🙌 #ReactLT
34 時間の都合上、実装例の解説は出来なかったため、 次回イベント or テックブログに乞うご期待…!👋 #ReactLT