React设计原理—1框架原理
阅读前须知
- 本文是笔者学习卡颂的《React设计原理》的读书笔记,对书中有价值内容以Q&A方式进行呈现,同时结合了自己的理解🤔
- 阅读时推荐先看问题,想想自己的答案,再和答案比对一下
- 本文属于前端框架科普,读完快速对前端框架有个概览👍
文章目录
- 前端框架原理概览
- 1 react是库还是前端框架?框架和库有啥区别?
- 2 如何理解前端框架的原理`UI = f(state)`
- 3 如何同时描述UI和逻辑
- 4 组件是存放UI和逻辑的松耦合单元,那么组件如何组织UI和逻辑
- 5 数据如何在组件间传递
- 6 前端框架分类
- 7 如何理解reduce和reducer
- 8 useReducer如何使用,和useState有什么关系区别,如何利用useReducer实现一个useState
- 9 react hooks中的自变量和因变量
- 前端框架使用的主流技术
- 1 useState如何实现state改变时,useEffect重新执行
- 2 useState如何实现state数值改变之后如何触发UI的更新
- 3 AOT和JIT有什么区别
- 4 利用AOT的框架(多适用于模板语法描述UI的框架)solid svelte
- 5 VDOM框架(jsx描述UI的框架+模板语法描述UI的框架)blockdom inferno
- 6 前端框架实现原理 🌟
- 6.1 元素级框架 svelte(AOT)
- 6.2 Vue3原理(组件级框架)
- 6.3 React原理(应用级框架)
- 前端框架总结
前端框架原理概览
1 react是库还是前端框架?框架和库有啥区别?
react本身是构建UI的库,将其称为框架是约定俗称的说法,其实不是框架

2 如何理解前端框架的原理UI = f(state)
框架f就是一个函数,自变量state是当前数据,因变量是宿主环境的视图
● state: 当前数据
● f:框架内部运行机制
○ 根据自变量的变化计算出UI的变化
○ 根据UI变化执行宿主环境的API
● UI:宿主环境的视图
3 如何同时描述UI和逻辑

4 组件是存放UI和逻辑的松耦合单元,那么组件如何组织UI和逻辑
state数据:自变量
f函数:是逻辑
UI:因变量
y=f(x) 自变量x的变化,可能会导致依赖x的因变量y的变化
const App = () => {const [count, setCount] = useState(0);// 自变量count改变导致因变量y1改变(纯函数)const y1 = useMemo(()=>count*2,[count]);// 有副作用useEffect(()=>{document.title="new title";console.log("副作用");},[])}

5 数据如何在组件间传递

当前组件的自变量或者因变量借助于UI传递给子组件,作为其自变量
子组件自身的自变量称为state
其他组件传递的自变量称为props

6 前端框架分类

7 如何理解reduce和reducer
reduce:函数式编程当中的一个术语,reduce操作被称为Fold折叠
// 数组中的reduce函数,第一个参数通常被称为reducer
const sum = [0, 1, 2].reduce((prev, item) => {return prev + item;
}, 0)
拿JavaScript来理解。reduce属于一种高阶函数,它将其中的回调函数reducer递归应用到数组的所有元素上并返回一个独立的值。这也就是“缩减”或“折叠”的意义所在了。
reducer:(state, action) => newState
redux中的reducer函数是因为它的入参和返回值都非常类似于arr的reduce中传入的回调函数
// reducer接收两个参数: state=[], action
// reducer返回值是一个新的state
const todoReducer = (state=[], action) => {switch(action){case "ADD":return [...state, {id: 111}];default:return state;}
}
8 useReducer如何使用,和useState有什么关系区别,如何利用useReducer实现一个useState
● useRedcuer是useState的替换方案,和useState相比,它更适合state逻辑复杂,或者state是个对象,包含多个子值,或者下一个state依赖于之前的stated的情况。相当于收敛逻辑于reducer函数中进行管理
● useReducer使用
const reducer = (state, action) => {switch (action) {case 'INCREMENT':return state + 1;case 'DECREMENT':return state - 1;default:return state;}
};function Reducer() {const [num, dispatch] = useReducer(reducer, 1);return (<div><p>useStateByReducer :<buttononClick={() => {// 区分dispatch函数和reducer函数dispatch('DECREMENT');}}>-</button>{num}<buttononClick={() => {dispatch('INCREMENT');}}>+</button></p></div>);
}
export default Reducer;
● 用useReducer实现一个useState
import { useReducer, useRef } from 'react';const isFunction = (fn) => {return Object.prototype.toString.call(fn) === '[object Function]';
};export default (initialState) => {const reducer = (state, action) => {return isFunction(action) ? action(state) : action;};return useReducer(reducer, initialState);
};
9 react hooks中的自变量和因变量

前端框架使用的主流技术
1 useState如何实现state改变时,useEffect重新执行
细粒度更新:依赖追踪技术如何实现的
实现useState的state和useEffect的双向绑定

function useState(value?: any) {/*** 问题:state绑定的不是回调函数,而是数据结构* 解法:创建一个数据结构:effect={execute: () => {}, deps: [subs1, subs2],}*/const subs: Set<Effect> = new Set();const getter = () => {// 问题:如何实现隐式绑定,如何知道执行getter时,所对应的effect// 解法:执行useEffect前,将effect加入堆栈,getter函数获取当前处于栈顶部的effect,即为当前执行的上下文,执行完之后,移出堆栈if (effectStack.length > 0) {const curEffect = effectStack[effectStack.length - 1];subscribe(subs, curEffect);}return value;};const setter = (newValue?) => {value = newValue;// emitfor (const sub of [...subs]) {console.log('setter emit subs');// debuggersub.execute();}};return [getter, setter];
}*** 创建一个的useEffect* 1 不需要显示指定依赖* 2 useEffect执行后,回调函数自动执行* 3 依赖变化时,useEffect自动执行*/
function useEffect(fn) {const execute = () => {// 每次执行,都会先删除依赖cleanup(effect);effectStack.push(effect);// 首次会执行一次回调,来触发“自动依赖收集”try {fn();} finally {effectStack.pop();}};const effect = {execute,deps: new Set<Set<Effect>>(), // III:使用set来存发布订阅的数据结构,而不是list};execute();
}/*** 双向删除订阅关系* @param effect*/
function cleanup(effect: Effect) {// console.log('cleanup', effect);// 找到useState的subs,清理该effect(在别人那里,清除自己的痕迹)for (const subs of [...effect.deps]) {subs.delete(effect);}// 清理effect的depseffect.deps.clear();
}/*** 双向订阅* @param subs* @param effect*/
function subscribe(subs, effect) {subs.add(effect);effect.deps.add(subs);
}
useMemo是useEffect包了一层
function useMemo(fn) {const [state, setState] = useState();useEffect(() => setState(fn()));return state();
}
2 useState如何实现state数值改变之后如何触发UI的更新
在编译阶段:AOT
在运行阶段VDOM:
3 AOT和JIT有什么区别

4 利用AOT的框架(多适用于模板语法描述UI的框架)solid svelte
用模板语法描述UI的框架可以从AOT中受益,因为模板语法中“静态”部分可以和“动态”部分很轻易的分离
从而减少框架在“自变量变化计算出UI变化”这部分工作量
5 VDOM框架(jsx描述UI的框架+模板语法描述UI的框架)blockdom inferno
VDOM是什么:虚拟DOM也是为了描述UI,为了实现“自变量变化计算出UI变化”
VDOM什么用:将元素描述的UI改成VDOM描述的UI,通过比较VDOM的变化,来计算UI的变化

VDOM好处
● 真实DOM元素冗余属性较多,没必要全部进行比较,减少内存开销
● 描述能力强大??
● 可以多平台渲染
6 前端框架实现原理 🌟
6.1 元素级框架 svelte(AOT)
Q: 如何建立自变量和UI元素的对应关系
编译器编译时绑定update方法和入参
Svelte编译器在编译<App/>时,直接追踪<script>标签中所有变量声明
一旦涉及count++/count=1等变量赋值的语句,该变量就会被提取到instance函数中,instance函数返回值作为组件的入参ctx
Q: 自变量变化时,如何更新UI元素
更新流程开始于元素,编译时已经绑定了具体元素
dirty可以指定自变量和元素的变化关系,set_data可以改dom
自变量变化时,标记dirty,调度更新fragment执行p方法,p方法内的if语句直接和dirty标记对应,执行set_data(), set_data函数会执行具体dom操作
编译时绑定UI和state的关系,触发变化时,标记dirty,更新入参,执行updateUI函数
等代码预先编译为create_fragment函数,创建dom,挂载,更新等
将state作为组件create_fragment的入参


function create_fragment(ctx) {let h1;let t;let dispose;return {c() {h1 = element("h1");t = text(/*count*/ ctx[0]);},m(target, anchor) {insert(target, h1, anchor);append(h1, t);// 在mount时候,绑定dom元素事件,回调函数dispose = listen(h1, "click", /*update1*/ ctx[1]);},p(ctx, [dirty]) {// count变,元素h1的t变,建立了自变量和元素的对应关系if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);},i: noop,o: noop,d(detaching) {if (detaching) detach(h1);dispose();}};
}// ctx 执行上下文 包括state和改变state的行为以及回调函数
function instance($$self, $$props, $$invalidate) {let count = 0;function update1() {// 触发ctx更新,dirty标记$$invalidate(0, count++, count);}setTimeout(() => {$$invalidate(0, count++, count);},1000);return [count, update1];
}
6.2 Vue3原理(组件级框架)
● 如何建立自变量和UI组件的对应关系
○ 细粒度更新
○ 每个组件都有一个watchEffect(类似useEffect),实现state变化时候,自动执行watchEffect中回调函数
● 自变量变化时,如何更新元素(更新流程开始于组件
○ 自变量变化,执行render函数,生成当前组件的VNode,和上一次生成的prevNode一起作为patch函数的入参,返回值为UI中变化的元素
watchEffect的回调函数中包括:render,patch一条龙

AOT如何帮助Vue3
<div><h1>hello</h1><p>{{name}}</p>
</div>
AOT后(识别模板代码,标记可能发生变化的量)
const render = (_ctx, cache) => {return(_openBlock(), _createElementBlock("div", null, [_createElementVNode("h1", null, "helllo"),// patchFlag 为1 表示变化的元素,为text, 2表示class_createElementVNode("p", null, _ctx.name, 1 /* TEXT*/)]))
}
// 生成的VNode大致表示成
const vnode = {tag: "div",children: [{tag: "h1", children: "hello"},{tag: "p", children: ctx.name, patchFlag: 1}],dynamicChildren:[{tag: "p", children: ctx.name, patchFlag: 1} ]
}
之后执行patch时,只需要比对dynamicChildren即可
6.3 React原理(应用级框架)
● 如何建立自变量和UI元素的对应关系
○ 不需要建立
● 自变量变化时,如何更新元素
○ 只要自变量改变,就从根节点开始,重新遍历应用,找到diff,执行dom

● react每次自变量变化都会从根节点遍历应用,会不会性能差?
不会
○ 内部有优化机制
○ 提供一些优化api,减少不必要的遍历: shouldComponentUpdate,memo,PureComponent等
前端框架总结

相关文章:
React设计原理—1框架原理
阅读前须知 本文是笔者学习卡颂的《React设计原理》的读书笔记,对书中有价值内容以Q&A方式进行呈现,同时结合了自己的理解🤔阅读时推荐先看问题,想想自己的答案,再和答案比对一下本文属于前端框架科普,…...
(C00034)基于Springboot+html前后端分离技术的宿舍管理系统-有文档
基于Springboothtml技术的宿舍管理系统-有文档项目简介项目获取开发环境项目技术运行截图项目简介 基于Springboothtml的前后端分离技术的宿舍管理系统项目为了方便对学生宿舍进行管理而设计,分为后勤、宿管、学生三种用户,后勤对整体宿舍进行管理、宿管…...
Flink面试题
一 基础篇Flink的执行图有哪几种?分别有什么作用Flink中的执行图一般是可以分为四类,按照生成顺序分别为:StreamGraph-> JobGraph-> ExecutionGraph->物理执行图。1)StreamGraph顾名思义,这里代表的是我们编写…...
Python学习笔记
前言:又从仓库翻出来了一些以前总结的文档,以下内容是我初学Python时网上找的或是图书馆借书抄写的笔记,现在再看有点零散不成体系,但是也还是纪念一下子吧。 Python学习笔记 对于初学编程的人来说,Python可以缩短编…...
最适合入门的100个深度学习实战项目
🚨注意🚨:最近经粉丝反馈,发现有些订阅者将此专栏内容进行二次售卖,特在此声明,本专栏内容仅供学习,不得以任何方式进行售卖,未经作者许可不得对本专栏内容行使发表权、署名权、修改…...
AssertionError: 618 columns passed, passed data had 508 columns【已解决】
问题描述 程序中断,报错如下AssertionError: 618 columns passed, passed data had 508 columns Exception has occurred: ValueError 618 columns passed, passed data had 508 columns AssertionError: 618 columns passed, passed data had 508 columnsThe abo…...
166_技巧_Power BI 窗口函数处理连续发生业务问题
166_技巧_Power BI 窗口函数处理连续发生业务问题 一、背景 在生产经营的数据监控中,会有一类指标需要监控是否连续发生,从而根据其在设定区间中的连续频次来评价业务。 例如: 员工连续迟到天数。销售金额连续上升或者下降。用户连续登陆…...
电子科技大学人工智能期末复习笔记(五):机器学习
目录 前言 监督学习 vs 无监督学习 回归 vs 分类 Regression vs Classification 训练集 vs 测试集 vs 验证集 泛化和过拟合 Generalization & Overfitting 线性分类器 Linear Classifiers 激活函数 - 概率决策 ⚠线性回归 决策树 Decision Trees 决策树构建递归…...
使用DDD指导业务设计的总结思考
领域驱动设计(DDD) 是 Eric Evans 提出的一种软件设计方法和思想,主要解决业务系统的设计和建模。DDD 有大量难以理解的概念,尤其是翻译的原因,某些词汇非常生涩,例如:模型、限界上下文、聚合、…...
面试官问:如何确保缓存和数据库的一致性?
如果你对这个问题有过研究,应该可以发现这个问题其实很好回答,如果第一次听到或者第一次遇到这个问题,估计会有点懵,今天我们来聊聊这个话题。 1、问题分析 首先我们来看看为什么会有这个问题! 我们在日常开发中&am…...
16.数据库Redis
一、基本概念 Redis(Remote Dictionary Server)译为“远程字典服务”,它是一款基于内存实现的键值型 NoSQL 数据库, 通常也被称为数据结构服务器,这是因为它可以存储多种数据类型,比如 string(字…...
【Redis高级-集群分片】
单机安装Redis首先需要安装Redis所需要的依赖:yum install -y gcc tclRedis安装包上传到虚拟机的任意目录:我放到了/tmp目录:解压缩:tar -zxvf /tmp/redis-6.2.4.tar.gz -C /tmp解压后:进入redis目录:cd /t…...
CSDN - CSDN27题解
文章目录幸运数字题目描述解题思路AC代码投篮题目描述解题思路AC代码通货膨胀-x国货币题目描述解题思路AC代码最后一位题目描述解题思路AC代码CSDN编程竞赛报名地址:https://edu.csdn.net/contest/detail/41 这次题目描述刚开始好像有些问题,之后被修正了…...
docker拉取mysql
搜索mysql版本docker search mysql搜索获赞数(星星数量) 大于 1000 的镜像docker search --filterstars1000 mysql搜索官方发布的版本docker search --filter is-officialtrue mysql搜索版本号docker search mysql57拉取docker pull devbeta/mysql57查看下载镜像docker images启…...
在Linux上安装Python3
记录:373场景:在CentOS 7.9操作系统上,安装Python-3.8.9环境。版本:JDK 1.8 Python-3.8.9官网地址:https://www.python.org下载地址:https://www.python.org/ftp/python/1.安装基础依赖1.1安装gcc(1)安装命…...
23 种设计模式的通俗解释,看完秒懂
01 工厂方法 追 MM 少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是 MM 爱吃的东西,虽然口味有所不同,但不管你带 MM 去麦当劳或肯德基,只管向服务员说「来四个鸡翅」就行了。麦当劳和肯德基就是生产鸡翅的 Factory 工厂模式&…...
如何做好需求管理?经验方法、模型、工具
需求管理能力是衡量产品经理能力的一个重要指标。因为需求是产品的基石,只有选取恰当的方法进行需求分析及管理,才能更好的构建产品方案,从而输出精准的产品定义。结合本人学习和自身经验,打算将需求管理分”需求挖掘”、”需求分…...
怎么用期货做风险对冲(如何利用期货对冲风险)
不同期货市场的同一期货品种的对冲交易怎么做 不同 期货市场 的同一期货品种的 对冲交易 。 因为地域和 制度环境 不同,同一种期货品种在不同市场的同一时间的价格很可能是不一样的,并且也是在不断变化的。 这样在一个市场做多头买进࿰…...
C++标准模板库type_traits源码剖析
一、type_traits源码介绍 1、type_traits是C11提供的模板元基础库。 2、type_traits可实现在编译期计算。包括添加修饰、萃取、判断查询、类型推导等等功能。 3、type_traits提供了编译期的true和false。 二、type_traits的作用 1、根据不同类型,模板匹配不同版本…...
Python获取公众号(pc客户端)数据,使用Fiddler抓包工具
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 今天来教大家如何使用Fiddler抓包工具,获取公众号(PC客户端)的数据。 Fiddler是一个http协议调试代理工具,它能够记录并检查所有你的电脑和互联网之间的http通讯,…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:
一、属性动画概述NETX 作用:实现组件通用属性的渐变过渡效果,提升用户体验。支持属性:width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项: 布局类属性(如宽高)变化时&#…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
