react17源碼解讀-hooks原理

理念

代數(shù)效應(yīng):把副作用從函數(shù)調(diào)用中剝離出去

// 一個獲取總評論數(shù)的需求
async function getTotalCommentNum(id1,id2){
  const num1=await getCommentNum(id1)
  const num1=await getCommentNum(id2)
  return num1+num2
}
// async await 具有傳染性,調(diào)用這個函數(shù)的函數(shù)也需要async await,這個會導(dǎo)致復(fù)雜性增加

為了避免以上傳染性, 我們虛構(gòu)一個語法

// try handle
function getTotalCommentNum(id1,id2){
  const num1= getCommentNum(id1)
  const num1= getCommentNum(id2)
  return num1+num2
}
function getCommentNum(id){
  const num = perform id;
  return num
}

try{
  getTotalCommentNum(1,2)
}handle(id){
  fetch('xxx.json?id='+id).then(num=>{
    resume with num;
  })
}

模擬的語法是這樣的getTotalCommentNum執(zhí)行會調(diào)用getCommentNum,getCommentNum的perform會觸發(fā)handle,handle中調(diào)用接口返回后 執(zhí)行resume with會將num返回到getCommentNum中,當(dāng)每個getCommentNum函數(shù)執(zhí)行完拿到num最后getTotalCommentNum中得到num1+num2的結(jié)果。

// 將以上的語法做一些改變可以發(fā)現(xiàn)是這樣的
function TotalCommentNum(id1,id2){ //類似于react中的組件
  const num1= useCommentNum(id1)
  const num1= useCommentNum(id2)
  return num1+num2;
}
function useCommentNum(id){// 類似于react中的hooks
  // const num = perform id;
  // return num
  const [num, updateNum] = useState(0);
  useEffect(()=>{
    fetch('xxx.json?id='+id).then(num=>{
      updateNum(num)
    })
  },[id])
}
//  以下就是react內(nèi)部幫我們實現(xiàn)的東西
try{
   TotalCommentNum(1,2)
}handle(id){
  // fetch('xxx.json?id='+id).then(num=>{
    // resume with num;
  // })
}

實現(xiàn)hooks
function App(){
  const [num ,updateNum] = useState(0);
  const [num1 ,updateNum1] = useState(0);
  // return <p onclick = { ()=>{updateNum(num + 1)} }>{num}</p> // 簡化jsx。。。忽略此處。。。。
  return {
    onclick(){
      updateNum(num+1);
      updateNum(num+1);
    }
  }
}

let isMount  = true; //全局變量模擬是mount階段還是update階段,最初始應(yīng)該是mount階段。
let workInProgressHook=null;// 保存當(dāng)前正在處理哪個hook,指向當(dāng)前hook的指針

const fiber = {
  stateNode: App,//組件本身
  memoizedState: null,// 函數(shù)類型的memoizedState保存useState變量,如果是class組件,會保存state的變量(保存的是一個鏈表)
  
  
}
function useState(initialState){
  let hook;
  if(isMount){ // 初次渲染
    hook={
       memoizedState : initialState,// 保存state的初始值
       next:null,
       queue:{ // 隊列 保存狀態(tài)改變的action
        pending:null
      }
    }
    if(!fiber.memoizedState){// 如果鏈表上沒有東西,把當(dāng)前hook掛在上邊
      fiber.memoizedState=hook;
    }else{
       workInProgressHook.next=hook//把hook串成鏈表,處理一個組件重復(fù)調(diào)用useState的情況
    }
    workInProgressHook=hook;//改變處理hook的指針
    //以上 在mount階段中,我們?yōu)槊總€useState都創(chuàng)建了hook,并且將這些hook用next連接成了一條鏈表,在update時就已經(jīng)有一條鏈表了。
  }else{
    hook= workInProgressHook;
    workInProgressHook=workInProgressHook.next;
  }
  // 因為所有的hook都是保存在鏈表中的,并且鏈表的順序是固定的,所有useState不能放在條件判斷語句或計時器中。

  let baseState = hook.memoizedState;//基礎(chǔ)的state
  if(hook.queue.pending){// 如果本次更新有新的update需要被執(zhí)行
    let firstUpdate = hook.queue.pending.next;// 取第一個update
    do{// 遍歷環(huán)狀鏈表
      const action = firstUpdate.action;// 取出對應(yīng)action
      baseState = action(baseState);// 根據(jù)舊的state用action計算出新的state狀態(tài)
      firstUpdate=firstUpdate.next;// 計算下一個
    }while(firstUpdate!== hook.queue.pending.next)// 當(dāng)firstUpdate不等于最開始的鏈表節(jié)點代表遍歷完了
    hook.queue.pending=null;// 將鏈表計算完,清空鏈表
  }
  hook.memoizedState= baseState;// 更新初始memoizedState
  return [baseState ,dispatchAction.bind(null ,hook.queue)]
}

function dispatchAction(queue,action){
  const update = {
    action,
    next:null
  }
  if(queue.pending === null){// 環(huán)狀鏈表
    // u0->u0
    update.next=update
  }else{
    //u1->u0->u1
    update.next = queue.pending.next// 將u1指向u0
    queue.pending.next = update // 將u0指向u1
  }
  queue.pending=update;
}

function schedule(){ // 調(diào)度
  workInProgressHook= fiber.memoizedState;
  const app = fiber.stateNode() // 調(diào)度組件執(zhí)行
  isMount = false// 調(diào)度后就不在是mount階段
  return app;
  
}


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容