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 Hooksの実装を探検してみる / Explore the React Hooks...
Search
193Otani
July 28, 2022
Programming
130
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
React Hooksの実装を探検してみる / Explore the React Hooks implementation
193Otani
July 28, 2022
Other Decks in Programming
See All in Programming
変わらないものが、変わるものを決める — 意図駆動開発 × イベントソーシング × イミュータブル | What Doesn't Change Decides What Can — IDD × Event Sourcing × Immutability
tomohisa
0
1.7k
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.9k
【QA Test Talk Vol.8】AI-DLC による Whole Team Approach の加速
pkshadeck
PRO
0
180
freee が目指す データ マネジメント戦略 AI-Ready 時代を支える 攻めのガバナンスとは
freee
PRO
0
360
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
290
数百円から始めるRuby電子工作
tarosay
0
150
VibeCodingからAgenticWorkflowへ
starfish719
0
450
GDG Korea Android: 2026 I/O Extended ~ What's new in Android development tools
pluu
0
220
yield再入門 #phpcon
o0h
PRO
0
1.1k
React本体のコードリーディング
high_g_engineer
1
140
これって Effect でできたのでは? / TSKaigi Mashup Kansai #2
susisu
0
240
わからない話を追いかけたら、プログラミング言語を作る側にいた
ydah
3
500
Featured
See All Featured
Easily Structure & Communicate Ideas using Wireframe
afnizarnur
194
17k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
66
57k
How to build a perfect <img>
jonoalderson
1
5.9k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
610
The Impact of AI in SEO - AI Overviews June 2024 Edition
aleyda
5
1.2k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
540
The Myth of the Modular Monolith - Day 2 Keynote - Rails World 2024
eileencodes
28
3.6k
What the history of the web can teach us about the future of AI
inesmontani
PRO
1
650
Heart Work Chapter 1 - Part 1
lfama
PRO
8
36k
Information Architects: The Missing Link in Design Systems
soysaucechin
0
1.1k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
249
1.3M
Have SEOs Ruined the Internet? - User Awareness of SEO in 2025
akashhashmi
0
410
Transcript
React Hooksの実装を探検してみる 株式会社カオナビ プロダクト本部 サービス開発部 Data Frontier グループ 大谷 育未
自己紹介 # 経歴 • 2020年4月にカオナビに新卒入社 • 2年目からフロントエンドエンジニアとして本格的にスタート • 現在は機能拡充を中心としたチームにて活動中 •
趣味はダーツ、ゲーム、モータースポーツ ◦ 今年はF1がアツいです
目指すこと/目指さないこと # 目指すこと • Hooksが呼び出されたときReactがなにをしているのかをざっくり理解する • 調査の過程で出てきたReact内部の構造、キーワードを知ってもらう # 目指さないこと •
React / React Hooksの動作原理を完璧に理解する • 登場するキーワードについて完全に理解する
Reactとは? • .FUB چ'BDFCPPL ͱίϛϡχςΟʹΑͬͯ։ൃ͞Ε͍ͯΔɺ6*ߏஙͷͨΊ ͷKBWBTDSJQUϥΠϒϥϦ (JUIVC GBDFCPPLSFBDU •
ҎԼͷͭΛίϯηϓτͱͯ͠։ൃ͞Ε͍ͯΔ ◦ એݴతͳ7JFX ◦ ίϯϙʔωϯτϕʔε ◦ Ұֶश͢ΕɺͲ͜Ͱ͑Δ • 8FCϒϥβ͚ͷ6*։ൃʹՃ͑ɺ3FBDU/BUJWFΛ༻͍ͨϞόΠϧΞϓϦ ͷ։ൃʹར༻Ͱ͖Δ
React Hooksとは? • React 16.8から追加されたReactの新機能群 • 関数コンポーネント内でReactのstateやライフサイクルメソッドを使用する ことができる(クラスコンポーネント内では機能しない) • ビルトインですぐに利用できるHooksが用意されている
◦ useState, useEffect, useMemo etc…
今回のターゲットはuseEffect
useEffectとは? • 関数コンポーネント内で副作用を実行することができる ◦ 副作用とは? - ある処理を実行した結果他の処理に対して影響を伴うようなもの ◦ stateの値を更新する、APIの値を取得するなど •
useEffectに渡された副作用関数は画面のレンダリング後に発火される • クラスコンポーネントにおける以下のライフサイクルメソッドの代替機能 ◦ componentDidMount, componentDidUpdate, componentWillUnmount
useEffectの本体 • react/src/ReactHooks.js • ReactCurrentDispatcher.current.useEffect(create, deps)を返している ◦ create -> useEffectで実行させたい副作用関数
◦ deps -> 副作用関数が依存している変数の配列 // @flow export function useEffect( create: () => (() => void) | void, deps: Array<mixed> | void | null, ): void { const dispatcher = resolveDispatcher(); return dispatcher.useEffect(create, deps); } // @flow import ReactCurrentDispatcher from './ReactCurrentDispatcher'; function resolveDispatcher() { const dispatcher = ReactCurrentDispatcher.current; … // コメント省略 return ((dispatcher: any): Dispatcher); }
ReactCurrentDispatcherを見る • ReactCurrentDispatcher.js • currentの中身空っぽいんだけど? ◦ Dispatcher型がセットされるようだが...? ◦ react-reconcilerってなんだ? //
@flow import type {Dispatcher} from 'react- reconciler/src/ReactInternalTypes'; const ReactCurrentDispatcher = { /** * @internal * @type {ReactComponent} */ current: (null: null | Dispatcher), }; export default ReactCurrentDispatcher;
React-Reconcilerってなに? • Fiberという単位でコンポーネントの状態や更新情報を管理している ◦ Fiberは一つのコンポーネントに対して基本的に1:1で存在する ◦ FiberのTreeを構成し、さらに変更前と変更後の二つのTreeを比較することで、更 新が必要な差分の検出を行っている(Reconciliation) • Reconcilerはこの差分検出処理群
• コアロジックを共有することで、Webアプリやネイティブアプリにおける動 作の一貫性を保っている ◦ ブラウザ開発開発: React + React DOM ◦ モバイル向け開発: React + React Native
ReactにおけるFiberとは? • コンポーネントの状態や仮想DOM情報をもつオブジェクト • コンポーネントに対してFiberは必ず1つは存在している • ReactはFiberを連結リストとして持つことで、コンポーネントごとに状態や 更新管理を行うことができる
Reconcilerが行う差分検出のイメージ Reconciliation Current WorkInProgress Time 1 Time 2
結局、ReactCurrentDispatcher.currentの中身は? • renderWithHooks - ReactFiberHooks.new.js: L.373 • currentの中身はHooksDispatcherOnMount or HooksDispatcherOnUpdate
◦ 各Hookに対応した関数を持つオブジェクト ◦ OnMount: L.2420 ◦ OnUpdate: L. 2427 // ReactFiberHooks.new.js - L.373 … if (__DEV__) { ... } else { ReactCurrentDispatcher.current = current === null || current.memoizedState === null ? HooksDispatcherOnMount : HooksDispatcherOnUpdate; } …
HooksDispatcherOnMount • 各Hookに対応する初期化関数をもっている • OnUpdateの場合は更新関数が割り当てら れている ◦ useEffect: updateEffect const
HooksDispatcherOnMount: Dispatcher = { readContext, useCallback: mountCallback, useContext: readContext, useEffect: mountEffect, useImperativeHandle: mountImperativeHandle, …, useId: mountId, unstable_isNewReconciler: enableNewReconciler, };
mountEffect(...) • 特別な処理はなさそう • mounEffectImplに渡しているフラグが気になる // ReactFiberHooks.new.jp - L.1701 function
mountEffect( create: () => (() => void) | void, deps: Array<mixed> | void | null, ): void { if ( __DEV__ && … ) { return mountEffectImpl(...); } else { return mountEffectImpl( PassiveEffect | PassiveStaticEffect, HookPassive, create, deps, ); } }
mountEffectImpl(...) • mountWorkInProgressHook(...) - L.635 ◦ Effect Hookの状態管理ツリーに現在の状態が保存されたノ ードを追加 ◦
上記ノードが持っている情報ごと • pushEffect(...) - L. 1543 ◦ 現在のeffectの状態を保存したEffectノードを作成 し、Fiberが持っている更新キューに追加 ◦ 保存される情報には依存配列の状態を含む // ReactFiberHooks.new.js - L. 1662 function mountEffectImpl(fiberFlags, hookFlags, create, deps): void { const hook = mountWorkInProgressHook(); const nextDeps = deps === undefined ? null : deps; currentlyRenderingFiber.flags |= fiberFlags; hook.memoizedState = pushEffect( HookHasEffect | hookFlags, create, undefined, nextDeps, ); }
useEffectの初回呼び出し 1. useEffect(...)が呼び出されると最終的にmountEffectImpl(...)が呼ばれる 2. 新しいHookが実行されること、そのHookがEffect Hookによる更新であるこ とがFiberに伝えられる
2回目以降の動きはどうなるのか? • useEffectは基本的に毎レンダリング呼び出される • useEffectは引数として依存する変数の配列を渡すことができる • 依存配列の中身が変わらない場合はuseEffectの処理は実行されない useEffect(() => {
console.log(effectVal); },[effectVal]);
updateEffectImplに秘密が... • 入力される依存配列が過去に使用したものと一致するかチェックしている • 一致した場合、flagsの更新をしていない = useEffectの動作と一致している // L. 1674
const prevDeps = prevEffect.deps; if (areHookInputsEqual(nextDeps, prevDeps)) { hook.memoizedState = pushEffect(hookFlags, create, destroy, nextDeps); return; } } } currentlyRenderingFiber.flags |= fiberFlags; // 副作用を適用するフラグを立てる
useEffectの実装を追ってみて • എܠʹ͋Δ࣮ͷҙਤ։ൃνʔϜͷߟ͑ํʹ;ΕΔ͜ͱ͕Ͱ͖ͨ • ReconcilerɺFiberͷಋೖཧ༝ͳͲ • ίʔυΛඈͼඈͼͰ͏ඞཁ͕͋Δ+FiberΛར༻ͨ͠ཧํ๏ʹෆ׳ΕͰί ʔυΛͬͯཧղ͢ΔͷΘΓͱେม • React
Hooksଞʹ࣮͞Ε͍ͯΔͷͰɺڵຯ͕͋ΔํͬͯΈͯʁ ◦ ࣗuseEffectͷ࣮͏ͷͰർΕ·ͨ͠...
参考 • React-Fiber-Architecture • Reconciliation - React • An Introduction
to React Fiber - The Algorithm Behind React • React Fiberとその周りについて調べた