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
6.2k
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
47k
Other Decks in Technology
See All in Technology
LINEヤフーのフロントエンド組織・体制の紹介【24年12月】
lycorp_recruit_jp
0
530
UI State設計とテスト方針
rmakiyama
2
580
Turing × atmaCup #18 - 1st Place Solution
hakubishin3
0
480
社内イベント管理システムを1週間でAKSからACAに移行した話し
shingo_kawahara
0
180
Google Cloud で始める Cloud Run 〜AWSとの比較と実例デモで解説〜
risatube
PRO
0
100
KnowledgeBaseDocuments APIでベクトルインデックス管理を自動化する
iidaxs
1
260
複雑性の高いオブジェクト編集に向き合う: プラガブルなReactフォーム設計
righttouch
PRO
0
110
マルチプロダクト開発の現場でAWS Security Hubを1年以上運用して得た教訓
muziyoshiz
3
2.3k
プロダクト開発を加速させるためのQA文化の築き方 / How to build QA culture to accelerate product development
mii3king
1
260
NilAway による静的解析で「10 億ドル」を節約する #kyotogo / Kyoto Go 56th
ytaka23
3
380
Amazon SageMaker Unified Studio(Preview)、Lakehouse と Amazon S3 Tables
ishikawa_satoru
0
150
DUSt3R, MASt3R, MASt3R-SfM にみる3D基盤モデル
spatial_ai_network
2
110
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
33
1.5k
Writing Fast Ruby
sferik
628
61k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
5
450
Bootstrapping a Software Product
garrettdimon
PRO
305
110k
The MySQL Ecosystem @ GitHub 2015
samlambert
250
12k
The Cost Of JavaScript in 2023
addyosmani
45
7k
Designing for Performance
lara
604
68k
Rebuilding a faster, lazier Slack
samanthasiow
79
8.7k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Adopting Sorbet at Scale
ufuk
73
9.1k
Keith and Marios Guide to Fast Websites
keithpitt
410
22k
Chrome DevTools: State of the Union 2024 - Debugging React & Beyond
addyosmani
2
170
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