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;
    }
}
相关推荐
flying robot4 小时前
React的响应式
前端·javascript·react.js
GISer_Jing15 小时前
React+AntDesign实现类似Chatgpt交互界面
前端·javascript·react.js·前端框架
智界工具库16 小时前
【探索前端技术之 React Three.js—— 简单的人脸动捕与 3D 模型表情同步应用】
前端·javascript·react.js
我是前端小学生16 小时前
我们应该在什么场景下使用 useMemo 和 useCallback ?
react.js
我是前端小学生16 小时前
讲讲 React.memo 和 JS 的 memorize 函数的区别
react.js
资深前端之路1 天前
react面试题一
前端·javascript·react.js
傻小胖1 天前
react19新API之use()用法总结
前端·javascript·react.js
傻小胖1 天前
React 19 新特性总结
前端·javascript·react.js
傻小胖1 天前
react中hooks之 React 19 新 Hooks useActionState & useFormStatus用法总结
前端·react.js·前端框架
疯狂小料2 天前
React 表单处理与网络请求封装详解[特殊字符][特殊字符]
前端·react.js·php