2.基于Fiber架构实现一个简单的React-Hook实现

支持hook

第一个问题是我们要如何区分出class component和function commponent,react是通过在Component上定义一个isReactComponent方法来区分的。 大家可以看一下react作者Dan Abramov的overreacted.io/zh-hans/how... 这个方式来区分, 文章里面解决这个问题考虑到了许多的点 好多都是很难想到的

  • babel转义以后class会变成function

  • 存在多个react版本的问题 导致不能用 Child.prototype instanceof React.Component

js 复制代码
class Component {
    constructor(props) {
        this.props = props;
        this.state = this.state || {}
    }
    //这里
    isReactComponent() {
        return true;
    }

    setState(partialState) {
        //?Component的state是在哪里更新的
        //在resetNextUnitOfWork里面更新fiber节点上的partialState 然后在updateClassComponent把fiber上的partialState更新到Component上
        scheduleUpdate(this, partialState);
    } 
}

我们把这个判断的逻辑在reconcileChildArray加上去

js 复制代码
   if(element && !sameType) {
            /**
                这个情况stateNode没有创建,在下一次执行updateHostComponent or updateClassComponent的时候会创建
            */
            newFiber = {
                type: element.type,
                tag: typeof element.type === 'string'? HOST_COMPONENT: element.type.prototype.isReactComponent? ClASS_COMPONENT: FUNNCTION_COMPONENT,
                props: element.props,
                parent: wipFiber,
                effectTag: PLACEMENT 
            }
        }

ok现在我们实现一个方法来处理function类型的fiber节点

js 复制代码
function updateFunctionComponent(fiber) {
   wipFiber = fiber;
   hookIndex = 0;
   wipFiber.hooks = [];
   const newChildElements = wipFiber.type(wipFiber.props);
   reconcileChildArray(wipFiber, newChildElements);
}  

这里我们要把当前的fiber节点存到一个全局的变量wipFiber里面,这样hook里面才能访问到当前的fiber节点 hookIndex和wipFiber.hooks = []; 是什么作用?我们先定义一下useState这个hook,大家就知道了。

useState

因为useState是由用户来调用的,所以这里就不能把当前的fiber节点传到useState里面,只能把当前的fiber节点变成全局变量,useState里面才能访问

js 复制代码
function useState(initial) {    
    const oldHook = 
        wipFiber.alternate &&   
        wipFiber.alternate.hooks &&
        wipFiber.alternate.hooks[hookIndex]
    //如果没有调用当前setState,只是组件重新渲染调用useState, state里面还是上次渲染的值,不会变成初始值
    const hook = {
        state: oldHook?oldHook.state: initial,
        queue: []
    }

    //调用setState会先把action存到queue里面 然后在执行useState的时候执行queue
    const actions = oldHook? oldHook.queue: [];
    actions.forEach(action => {
        hook.state = action(hook.state);
    })

    const setState = value => {
        if(typeof value === "function") {
            hook.queue.push(value);
        } else {
            hook.state = value;
        }
        //class component 调用setState的时候可以通过class instance的__fiber属性找到当前的fiber节点 然后通过parent一直向上找到root fiber节点
        //hook没办法通过这种方式找到root fiber 只能通过把rootFiber变成全局变量的方式
        nextUnitOfWork = {
            tag: HOST_ROOT,
            stateNode: wipFiberRoot.stateNode,
            props: wipFiberRoot.props,
            alternate: wipFiberRoot
        }
        requestIdleCallback(performWork);
    }

    wipFiber.hooks.push(hook);
    hookIndex++;
    return [hook.state, setState];
}

调用setState的时候我们先把最新的值或者set function存到old fiber tree的hook上 然后开始重新构建fiber tree,重新构建fiber tree 就需要拿到old root fiber node,所以我们在前面声明了一个全局的wipFiberRoot用来存old root fiber node。

在重新构建fiber tree的时候我们会重新调用useState useState会从old fiber tree上就拿前面设置的值或者set function,然后计算出最新的state更新到最新的fiber tree。 可以看到useState是通过index来访问old fiber tree上面的对应的hook 所以必须保证每次渲染hooks的顺序不能变化,不然拿到的值就错乱了

dom更新阶段

只要在commitDeletion里面把FUNNCTION_COMPONENT的判断加上就可以了

js 复制代码
function commitDeletion(fiber, domParent) {
    let node = fiber;
    while (true) {
       //这里
      if (node.tag === ClASS_COMPONENT || node.tag === FUNNCTION_COMPONENT) {
        node = node.child;
        continue;
      }
      domParent.removeChild(node.stateNode);
      while (node != fiber && !node.sibling) {
        node = node.parent;
      }
      if (node == fiber) {
        return;
      }
      node = node.sibling;
    }
}
相关推荐
GISer_Jing1 小时前
React核心功能详解(一)
前端·react.js·前端框架
FØund4043 小时前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
疯狂的沙粒4 小时前
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
react.js·typescript
鑫宝Code5 小时前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架
沉默璇年14 小时前
react中useMemo的使用场景
前端·react.js·前端框架
红绿鲤鱼15 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
loey_ln17 小时前
FIber + webWorker
javascript·react.js
zhenryx18 小时前
前端-react(class组件和Hooks)
前端·react.js·前端框架
老码沉思录1 天前
React Native 全栈开发实战班 - 性能与调试之打包与发布
javascript·react native·react.js
沉默璇年1 天前
react中Fragment的使用场景
前端·react.js·前端框架