實驗三-電子公文傳輸系統1-個人貢獻
阿新 • • 發佈:2021-12-12
react原始碼解析14.手寫hooks
視訊講解(高效學習):進入學習
往期文章:
最關鍵的是要理解hook佇列和update佇列的指標指向和updateQueue的更新計算,詳細見視訊講解
import React from "react"; import ReactDOM from "react-dom"; let workInProgressHook;//當前工作中的hook let isMount = true;//是否時mount時 const fiber = {//fiber節點 memoizedState: null,//hook連結串列 stateNode: App//dom }; const Dispatcher = (() => {//Dispatcher物件 function mountWorkInProgressHook() {//mount時呼叫 const hook = {//構建hook queue: {//更新佇列 pending: null//未執行的update佇列 }, memoizedState: null,//當前state next: null//下一個hook }; if (!fiber.memoizedState) { fiber.memoizedState = hook;//第一個hook的話直接賦值給fiber.memoizedState } else { workInProgressHook.next = hook;//不是第一個的話就加在上一個hook的後面,形成連結串列 } workInProgressHook = hook;//記錄當前工作的hook return workInProgressHook; } function updateWorkInProgressHook() {//update時呼叫 let curHook = workInProgressHook; workInProgressHook = workInProgressHook.next;//下一個hook return curHook; } function useState(initialState) { let hook; if (isMount) { hook = mountWorkInProgressHook(); hook.memoizedState = initialState;//初始狀態 } else { hook = updateWorkInProgressHook(); } let baseState = hook.memoizedState;//初始狀態 if (hook.queue.pending) { let firstUpdate = hook.queue.pending.next;//第一個update do { const action = firstUpdate.action; baseState = action(baseState); firstUpdate = firstUpdate.next;//迴圈update連結串列 } while (firstUpdate !== hook.queue.pending);//通過update的action計算state hook.queue.pending = null;//重置update連結串列 } hook.memoizedState = baseState;//賦值新的state return [baseState, dispatchAction.bind(null, hook.queue)];//useState的返回 } return { useState }; })(); function dispatchAction(queue, action) {//觸發更新 const update = {//構建update action, next: null }; if (queue.pending === null) { update.next = update;//update的環狀連結串列 } else { update.next = queue.pending.next;//新的update的next指向前一個update queue.pending.next = update;//前一個update的next指向新的update } queue.pending = update;//更新queue.pending isMount = false;//標誌mount結束 workInProgressHook = fiber.memoizedState;//更新workInProgressHook schedule();//排程更新 } function App() { let [count, setCount] = Dispatcher.useState(1); let [age, setAge] = Dispatcher.useState(10); return ( <> <p>Clicked {count} times</p> <button onClick={() => setCount(() => count + 1)}> Add count</button> <p>Age is {age}</p> <button onClick={() => setAge(() => age + 1)}> Add age</button> </> ); } function schedule() { ReactDOM.render(<App />, document.querySelector("#root")); } schedule();