react hooks实现原理(useState为例)

2023-10-30

一、源代码

逻辑十分绕,建议多敲几遍。

let isMount = true; // 判断是挂载还是更新
let workInProgressHook;

// App组件对应的fiber对象
const fiber = {
    memorizedState: null,  // 当前hook的相关信息
    stateNode: App
}

function schedule() {
    // 更新前将workInProgressHook重置为fiber保存的第一个Hook
    workInProgressHook = fiber.memorizedState;

    const app = fiber.stateNode();
    isMount = false;

    return app; // 方便调试 触发事件
}

/**
 * 调用setState方法,相当于调用这个方法,从而实现state状态更新
 * @param {*} queue 
 * @param {*} action 
 */
function dispatchAction(queue, action) {
    const update = {
        action,
        next: null
    }

    // 环状链表
    if (queue.pending === null) {
        update.next = update;
    } else {
        update.next = queue.pending.next;
        queue.pending.next = update;
    }

    queue.pending = update;

    // 开始调度
    schedule();
}

// 手写hook
function useState (initalState) {
    let hook;

    // 最开始刚挂载的时候
    if (isMount) {
        hook = {
            queue: {
                pending: null
            },
            memorizedState: initalState,
            next: null
        }

        // 初始化时候 只调用一次 setState的情况
        if (!fiber.memorizedState) {
            fiber.memorizedState = hook;
        
            // 初始化的时候 有多个useState的情况
        } else {
            // 不断追加到链表后面
            workInProgressHook.next = hook;
        }

        workInProgressHook = hook;
    } 
    // 执行update操作的时候
    else {
        hook = workInProgressHook;
        workInProgressHook = workInProgressHook.next;
    }

    let baseState = hook.memorizedState;
    
    if (hook.queue.pending) {
        let firstUpdate = hook.queue.pending.next;

        do {
            const {action} = firstUpdate;
            baseState = action(baseState);
            firstUpdate = firstUpdate.next;
        } while(firstUpdate !== hook.queue.pending)

        hook.queue.pending = null;
    }

    hook.memorizedState = baseState;

    return [baseState, dispatchAction.bind(null, hook.queue)]
}


// 组件
function App() {
    const [state, setState] = useState(0);
    const [state2, setState2] = useState(1);

    console.log('workInProgressHook', workInProgressHook, state, state2)

    return {
        click () {
            setState(state => state + 1);
            setState(state => state + 1);
        },
        focus () {
            setState2(state2 => state2 + 1)
        }
    }
}

window.app = schedule();

二、参考资料

  1. React技术揭秘
  2. B站:React Hooks的理念、实现、源码
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

react hooks实现原理(useState为例) 的相关文章

随机推荐

  • Geotools与OGC(二)----WKT坐标系信息的读取

    WKT除了有针对几何信息的描述外 也有针对空间参考的描述 以下我直接套用OGC规范中的描述 https www osgeo cn doc ogcstd ogc standard ch02 chapter1 chapter html wkb
  • 每天坐6小时以上,死亡率会增高——但站着工作就管用吗?

    此篇文章来自一篇科普类文章 作为IT行业人士 每天坐着的时间几乎都已超过了6小时 我们这些久坐的同仁儿们需要关注自己的健康 运动是我们健康的砝码哦 英文原文 Why I killed my standing desk 想必很多上班族都深受颈
  • 为什么老程序员的效率如此高?

    首先 优秀得神枪手一定是靠子弹喂出来得 没有几千上万个子弹得真枪实战 就很难在战场上一击枪杀敌人 我经常会看到一些新手程序员在写代码的时候需要频繁的去查看文档或者是百度搜索各种接口的用法 有时写一个功能要查个几十次 很多时间都浪费在了搜索上
  • upload-labs大详解

    pass1 上传一个php一句话文件 记得改成php格式 发现不允许上传php类型的 只能上传jpg gif pngl的我们打算用burp抓包 先上传jpg的 然后用burp改成php的 放包后 找到它的存储位置 用蚁剑连接 成功连接 pa
  • ReactNative常用插件使用

    项目版本介绍 目前使用的项目node版本v14 17 5 npm版本6 14 14 reactNative项目使用的模板结合typescript语法的项目模板架构 安装的方式如下 npx react native init xxx 项目名
  • TensorFlow团队成员说:深度学习的未来,在单片机的身上

    便携栗 编译自 Pete Warden s Blog量子位 出品 公众号 QbitAI Pete Warden 是谷歌TensorFlow团队成员 也是TensorFLow Mobile的负责人 常年遨游在深度学习的大海 另外 这些看上去很
  • 如何判断视频的比例(4:3/16:9)和分辨率?

    如何区分16 9和4 3 将 视频分辨率的宽度除以高度 运算结果接近1 7的是16 9 超过1 77都归类为16 9 运算结果接近1 3的4 3 例如您要上传的视频分辨率是 640 480 用640 480 1 33 那么这个就是一个4 3
  • 阿里云服务器型号大全及机型如何选择(建议收藏)

    不同的阿里云实例规格可以提供的计算能力不同 适用于不同的业务场景和使用场景 1 根据使用场景来选择 下图显示了阿里云ECS的部分通用计算和异构计算实例规格族及其对应的业务场景 简单来看 g6e和g6型能够满足一般的通用需求 对于比如金融 政
  • electron打包:electron-packager及electron-builder两种方式实现桌面端应用程序打包

    electron vue初始化 electron vue初始化命令 vue init simulatedgreg electron vue my project 我们在初始化electron vue项目时 可以选择打包方式 electron
  • vue——移动端在线预览pdf并能缩放(pdfh5)

    最近接了一个需求需要在移动端预览pdf 并切要能缩放 百度发现大多推荐vue pdf 但是vue pdf这个包 安装之后运行报错 解决之后的实现效果不符合需求需要 而且 实现缩放功能的时候 整个canvas画布整个放大 虽然有放大效果 但是
  • 【华为OD统一考试B卷

    在线OJ 已购买本专栏用户 请私信博主开通账号 在线刷题 运行出现 Runtime Error 0Aborted 请忽略 华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一
  • GLSL ES中的布局限定符(layout)

    一 存储限定字 首先需要了解存储限定字才能正确认识布局限定符 在webGL中要实现着色器和JS代码之间的数据交互 主要靠三类变量 分类的依据是存储限定字 分别是 attribute uniform varying 其中attrbute和un
  • 校招笔试面试---算法题1

    牛牛取快递 dijkstra 邻接表存图 优先队列 链接 https www nowcoder com questionTerminal 071695ed1d0b4e65b07eb969d212b92a 来源 牛客网 时间限制 1秒 空间限
  • 用批处理完全卸载mysql,完全卸载mysql(停止服务、卸载相关程序、删除注册表

    1 停止服务MySQL 2 卸载mysql相关的程序 3 删除注册表 运行 gt regedit machine gt system gt controlset001 controlset002 currentcontrolset gt s
  • Qt5下遍历QList的方法

    lines定义如下 QMap
  • 阿波罗无法通过链接外网

    官方提供说明 官方地址 无法连接外网的原因通常是阿波罗走到内网 通过注册中心无法连接到服务 bin bash apollo config db info apollo config db url jdbc mysql localhost 3
  • 【C++】初级—类和对象之赋值运算符重载、取地址操作符重载和const修饰的取地址运算符重载

    在上一篇中写到 一个类会产生的6种默认函数中的前三个默认函数 1 构造函数 2 析构函数 3 拷贝构造函数 4 赋值运算符重载 5 取地址操作符重载 6 拷贝构造函数 这次将着重讲解后三个函数 赋值运算符重载 运算符重载 什么是运算符重载呢
  • CSS字体的单位

    长度单位 1 像素 px 实际上是屏幕上的一个个小点 100px 100个小点 这个点 正常情况我们是看不到 如果我们把一个内容放大很多倍 就可以看到了 在pc端 电脑端 一般情况下1px 1个发光点 也是我们最常用的长度单位 它是固定单位
  • “区块链”技术在传统行业中的应用

    点击上方 中兴开发者社区 关注我们 每天读一篇一线开发者原创好文 比特币可能是一场庞氏骗局 但区块链技术却真实存在 2013年以来 比特币受到了全世界投资者的狂热追捧 虽然几经涨跌 大部分国家监管方对其态度也不甚明朗 但作为比特币底层技术的
  • react hooks实现原理(useState为例)

    一 源代码 逻辑十分绕 建议多敲几遍 let isMount true 判断是挂载还是更新 let workInProgressHook App组件对应的fiber对象 const fiber memorizedState null 当前h