react17源码解读-hooks原理

理念

代数效应:把副作用从函数调用中剥离出去

// 一个获取总评论数的需求
async function getTotalCommentNum(id1,id2){
  const num1=await getCommentNum(id1)
  const num1=await getCommentNum(id2)
  return num1+num2
}
// async await 具有传染性,调用这个函数的函数也需要async await,这个会导致复杂性增加

为了避免以上传染性, 我们虚构一个语法

// 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执行会调用getCommentNum,getCommentNum的perform会触发handle,handle中调用接口返回后 执行resume with会将num返回到getCommentNum中,当每个getCommentNum函数执行完拿到num最后getTotalCommentNum中得到num1+num2的结果。

// 将以上的语法做一些改变可以发现是这样的
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内部帮我们实现的东西
try{
   TotalCommentNum(1,2)
}handle(id){
  // fetch('xxx.json?id='+id).then(num=>{
    // resume with num;
  // })
}

实现hooks
function App(){
  const [num ,updateNum] = useState(0);
  const [num1 ,updateNum1] = useState(0);
  // return 

{updateNum(num + 1)} }>{num}

// 简化jsx。。。忽略此处。。。。 return { onclick(){ updateNum(num+1); updateNum(num+1); } } } let isMount = true; //全局变量模拟是mount阶段还是update阶段,最初始应该是mount阶段。 let workInProgressHook=null;// 保存当前正在处理哪个hook,指向当前hook的指针 const fiber = { stateNode: App,//组件本身 memoizedState: null,// 函数类型的memoizedState保存useState变量,如果是class组件,会保存state的变量(保存的是一个链表) } function useState(initialState){ let hook; if(isMount){ // 初次渲染 hook={ memoizedState : initialState,// 保存state的初始值 next:null, queue:{ // 队列 保存状态改变的action pending:null } } if(!fiber.memoizedState){// 如果链表上没有东西,把当前hook挂在上边 fiber.memoizedState=hook; }else{ workInProgressHook.next=hook//把hook串成链表,处理一个组件重复调用useState的情况 } workInProgressHook=hook;//改变处理hook的指针 //以上 在mount阶段中,我们为每个useState都创建了hook,并且将这些hook用next连接成了一条链表,在update时就已经有一条链表了。 }else{ hook= workInProgressHook; workInProgressHook=workInProgressHook.next; } // 因为所有的hook都是保存在链表中的,并且链表的顺序是固定的,所有useState不能放在条件判断语句或计时器中。 let baseState = hook.memoizedState;//基础的state if(hook.queue.pending){// 如果本次更新有新的update需要被执行 let firstUpdate = hook.queue.pending.next;// 取第一个update do{// 遍历环状链表 const action = firstUpdate.action;// 取出对应action baseState = action(baseState);// 根据旧的state用action计算出新的state状态 firstUpdate=firstUpdate.next;// 计算下一个 }while(firstUpdate!== hook.queue.pending.next)// 当firstUpdate不等于最开始的链表节点代表遍历完了 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){// 环状链表 // 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(){ // 调度 workInProgressHook= fiber.memoizedState; const app = fiber.stateNode() // 调度组件执行 isMount = false// 调度后就不在是mount阶段 return app; }

你可能感兴趣的:(react17源码解读-hooks原理)