2020 年 07 月討論 === ## 蒼時 ## 資料 * [Deep dive: How do React hooks really work?](https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/) * [React Hooks 不是黑魔法,只是陣列](https://andyyou.github.io/2019/07/29/hooks-not-magic-just-arrays/) * [原文](https://medium.com/@ryardley/react-hooks-not-magic-just-arrays-cd4f1857236e) * [Vue 作者 Hooks 實驗](https://github.com/yyx990803/vue-hooks) * [Making Sense of React Hooks](https://medium.com/@dan_abramov/making-sense-of-react-hooks-fdbde8803889) * [React Hooks RFC](https://github.com/reactjs/rfcs/pull/68) ## 實驗 * [useState 模擬](https://jsbin.com/releniv/edit?html,js,output) ## React Hook ### `resolveDispatcher` [原始碼](https://github.com/facebook/react/blob/master/packages/react/src/ReactHooks.js#L28) 不確定怎麼拿到,不過 React 有好幾種情況都會實作,同時這個只有在 React Component 裡面執行時才能拿到。 > 先假設他是 Dispatcher 的實作,簡單說是某個 Component 內的 Dispatcher ### `useState` 一樣有好幾個版本,這邊用比較新的 `ReactFiber` 當參考 這些會定義在 `ReactFiberHooks.new.js` 的 [Dispatcher](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L1775) 區段,根據不同情況會設置不同的 Dispatcher 不同階段會做不同處理,像是 [`onMount`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L1971) 的時候會使用 [`mountState`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L1143) 來處理。 > `mountState` 會透過 Hook 製作出一個狀態,然後把初始狀態儲存進去,如果初始狀態是 `function` 會呼叫後獲取對應的數值, #### `mountState` * `updateWorkInProgressHook` 產生 Hook 設定初始值 * 製作出 Queue (把初始狀態放在裡面) * 製作出 Dispatch(透過 `dispatchAction.bind` 產生用來更新 State 的方法) * 回傳 Hook 指向的數值跟 Dispatch 方法 > [`dispatchAction`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L1662) 是一個方法,裡面實作了對 Queue 的操作 #### `updateState` * 呼叫 `updateReducer` > [`updateReducer`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L665) 裡面實作的大致上就是把 Queue 進行實際處理的操作 #### `renderState` * 呼叫 `rerenderReducer` * 回傳新的狀態跟原本的 Dispatch > [`rerenderReducer`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L813) 會做類似 `mountState` 的處理產生新的 Hook 並且把前一個狀態放到這個 Hook 產生的 Queue 作為前一個狀態 #### `updateWorkInProgressHook` [`updateWorkInProgressHook`](https://github.com/facebook/react/blob/master/packages/react-reconciler/src/ReactFiberHooks.new.js#L566) 會在一個大的 Stack 裡面取出目前的狀態,然後產生 Hook 物件回傳。 ### 簡易分析 基本上 React Hook 的簡化之後,基本上就跟前面文章提到透過陣列跟指標處理的概念類似,但是裡面又再細分出非常多機制,並且依據不同處理階段進行對應的處理。 > 想放棄治療了 QQ ## Vue Composition API ### `reactive` [原始碼](https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/reactive.ts#L123:10) 類似 `useState` 的做法,不過跟 Vue 的習慣一樣會使用 Proxy 來封裝,因此中間會經過不同的確認: 1. 是否已經是 Proxy 2. 是否可以封裝 最後在基於傳入的 Handler 產生對應的 Observe 物件回傳 ### `effect` [原始碼](https://github.com/vuejs/vue-next/blob/master/packages/reactivity/src/effect.ts#L79) 主要是透過 `createReactiveEffect()` 製作出一個 Function(物件)然後再被呼叫的時候會去執行丟給 `effect` 的 `fn` 來當作回傳值,中間會用 `effectStack` 確保每次只會執行該 Effect 一次。 ### `watchEffect` [原始碼](https://github.com/vuejs/vue-next/blob/44e6da1402fa2b6f5a0a0c692cd693a8ff1a40a3/packages/runtime-core/src/apiWatch.ts#L133) 會呼叫 `doEffect` 實行,做以下處理 1. 檢查觀察對象的類型 2. 依照類型定義 `getter()` 方法 3. 定義 `cleanup()` 方法 4. 如果有 SSR or Node.js 則先直接執行看看 5. 製作 `applyCb()` 的方法來呼叫 Callback 6. 依照 `flush` 設定 `scheduler()` 方法 7. 使用 `effect()` 製作 `runner` 8. ` recordInstanceBoundEffect()` // 推測是紀錄長出來的 Effect => 會放到 `currentInstance.effects` 陣列中 9. 先執行一次(`runner` 照設定可能會是 Callback 的 `applyCb()`) 10. 回傳停止的方法 ## 西瓜 https://hackmd.io/AeHZcCnlRqeQ4PGnGHRj7A ## Cindy https://hackmd.io/@cindyliu923/SyVy8h2kw