美文网首页
react17源码解读-hooks原理

react17源码解读-hooks原理

作者: Mr无愧于心 | 来源:发表于2022-02-28 13:58 被阅读0次
    理念

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

    // 一个获取总评论数的需求
    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 <p onclick = { ()=>{updateNum(num + 1)} }>{num}</p> // 简化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原理

          本文链接:https://www.haomeiwen.com/subject/elbacrtx.html