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;
    }
}
相关推荐
kyriewen10 小时前
AI 写的 React 组件,合并前必查的 6 个坏味道——每个都有代码对比
前端·javascript·react.js
光影少年14 小时前
RN适配方案:屏幕适配、分辨率适配、刘海屏/全面屏适配
react native·react.js·掘金·金石计划
Charonmomo15 小时前
react/antd - 不能正确打开标签页问题记录
前端·react.js·前端框架
用户6000718191016 小时前
【翻译】React Compiler 详解---memo
react.js
爱分享的程序猿-Clark17 小时前
【前端开发】前端开发者如何使用 Claude Code 快速搭建 React 项目!(小白都能学会的教程)
前端·react.js
大尚来也19 小时前
React Hooks全解析:告别繁琐Class组件
前端·react.js·前端框架
allnlei21 小时前
React + FastAPI 前后端分离架构下的 Nginx 配置实践
react.js·架构·fastapi
LaughingZhu21 小时前
Product Hunt 每日热榜 | 2026-07-15
前端·人工智能·神经网络·react.js·搜索引擎·前端框架
光影少年1 天前
RN中的StyleSheet.create 好处、内联样式弊端
react native·react.js·掘金·金石计划
我是大卫1 天前
【图】React源码解析-第六部分:高级算法与执行链路
react.js·源码