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;
    }
}
相关推荐
不可食用盐14 小时前
# AI开发基于 Tauri 2 + React 的所见即所得 Markdown 编辑器
react.js·rust·ai编程
光影少年16 小时前
useMemo 与 useCallback 区别、各自解决什么性能问题、依赖陷阱
react.js·前端框架·掘金·金石计划
骑自行车的码农19 小时前
react hooks原理:为什么不能在条件中使用 hook ?
vue.js·react.js
Highcharts.js19 小时前
无需搭建数据管道,如何快速上线投资基金筛选器?
开发语言·javascript·react.js·前端框架·highcharts
接着奏乐接着舞19 小时前
react native expo打包
javascript·react native·react.js
水云桐程序员21 小时前
Web应用的分类
前端·javascript·vue.js·react.js·webkit
暗不需求1 天前
深入理解 React 受控组件与非受控组件:从源码到面试
前端·react.js·面试
声声codeGrandMaster1 天前
React框架的基础代码使用
前端·react.js·前端框架
Highcharts.js1 天前
Highcharts React 5.0 正式版:支持 ES 模块化、组件更精简、开发体验全面升级
前端·javascript·react.js·elasticsearch·前端框架·highcharts
光影少年1 天前
react的useRef 作用:获取DOM、保存可变数据、区别 createRef
前端·javascript·react.js