《React设计原理》读书分享–前端框架概述

简介: 《React设计原理》读书分享–前端框架概述

很早就阅读了电子版的《React技术揭秘》,后来听说出了实体书,果断就下单了

所以今天分享下最近的阅读心得

基本原理

概述

前端框架主要的作用是将数据的变化映射为UI的变化:

UI=fn(state)

fn就是计算数据的变动导致UI是如何变化的,不同的框架中,fn的描述方式不同

主流的描述方式分为:

  1. jsx:使UI和逻辑更紧密,它是ES语法糖.(从逻辑出发,扩展逻辑,描述UI)
  2. 模板语法:使用HTML描述UI,它是HTML语法扩展。(从UI出发,扩展UI,描述逻辑)

jsx是动态的,即使代码没有边,每次更新,都会重新编译,

模板语法是静态的,可以用来分析,哪些节点是动态的,哪些节点是静态的。有很大的优化空间。

不管是jsx还是模板语法,它们都是组织逻辑和UI的关系

// react
const [count, setCount] = useState(0)
<div onClick={() => setCount(conut++)}>{count}</div>
// Vue
const count = ref(0)
<div @click={count.value++}>{count.value}</div>
// Svelte
const let = 0
<div on:click={() => conut++}>{count}</div>

上面三块代码功能都是一样的:当count发生变化时,UI跟着变化

根据UI变化方式(更新细粒度)不同,将框架可以分为三类:

  1. 应用级:数据变化时,重新渲染整个应用,React
  2. 组件级:数据变化时,重新渲染数据有变化的组件Vue
  3. 元素级:数据变化时,只渲染数据变化的DOM节点,Svelte

按下性能问题暂且不表,先想想,为啥会有这种差别呢?

这是因为不同的框架,架构不同导致的。

我们的代码并不是立即执行的,而是先进行编译(语法转换、将ts转为js、压缩、polyfill等),将我们的代码转为宿主环境可以识别的代码。

React

React经过编译之后返回的是createElement函数,所以每次数据变化,React都会从应用根节点重新加载整个应用。

export const App = () => {
  const [count, setCount] = useState(0);
  return /*#__PURE__*/React.createElement("div", {
    onClick: () => setCount(conut++)
  }, count);
};

所以这种框被架称为应用级框架

Vue

Vue经过编译之后返回的是组件的render函数,

function render(_ctx, _cache, $props, $setup, $data, $options) {
  return (_openBlock(), _createElementBlock("h1", {
    onClick: _cache[0] || (_cache[0] = $event => (_ctx.count++))
  }, _toDisplayString(_ctx.count), 1 /* TEXT */))
}

Vue3会为每个组件建立watchEffect事件,这个大致如下:

// patch是对比前后VNode变化的方法
watchEffect(() => patch(render(props), preVDOM), [conut])

在页面首次进入或者watchEffect的依赖项发生变化时,都会调用组件的render函数。

render函数的返回值是本次更新的VNode,Vue会根据本次更新的VNode与上传更新做比较(patch),找到最优的更新路径,并且进行更新。

所以这种框架被称为组件级框架

Svelte

Svelte经过编译之后的返回值如下:(先别晕,可以跳过代码往下看)

import {
    SvelteComponent,
    append,
    detach,
    element,
    init,
    insert,
    listen,
    noop,
    safe_not_equal,
    set_data,
    text
} from "svelte/internal";
function create_fragment(ctx) {
    let div;
    let t;
    let mounted;
    return {
        c() {
            div = element("div");
            t = text(/*count*/ ctx[0]);
        },
        m(target, anchor) {
            insert(target, div, anchor);
            append(div, t);
            if (!mounted) {
                dispose = listen(div, "click", /*click_handler*/ ctx[1]);
                mounted = true;
            }
        },
        p(ctx, [dirty]) {
            if (dirty & /*count*/ 1) set_data(t, /*count*/ ctx[0]);
        },
        d(detaching) {
            if (detaching) detach(div);
            mounted = false;
            dispose();
        }
    };
}
function instance($$self, $$props, $$invalidate) {
    let count = 0;
    const click_handler = () => $$invalidate(0, count++, count);
    return [count, click_handler];
}
class App extends SvelteComponent {
    constructor(options) {
        super();
        init(this, options, instance, create_fragment, safe_not_equal, {});
    }
}
export default App;

Svelte返回的值主要包括三块:

1.create_fragment函数:

  1. c方法:create元素div的操作。
  2. m方法:mounted时执行将创建的div插入,并且监听divclick事件.
  3. d方法:delete元素div的操作。
  4. p方法:updata数据的操作。

2.instance函数:

声明在模板使用的变量,以及变量变化时的回调函数,并且返回它们(其实就是ctx上下文)。

3.继承SvelteComponent的组件,并且执行init方法

init方法的大致逻辑是:当数据变化,触发mounted阶段监听事件的回调函数,这个回调函数就是instance函数返回值里的click_handler,即ctx[1]

如果仅仅声明了但是没有在模板中使用,那么就会作为第四块,单独声明,但这里就不做赘述了。

从前面的代码可以看出:Svelte在编译阶段,就已经找到元素和变量之间的对应关系了。

所以这种框被架称为元素级框架

React性能

你肯定会问,我就改了个count的值,像React这样大动干戈,重新渲染整个应用,是不是很低效啊。

其实,React在运行时阶段,做了一部分关键的优化。

不管是Vue还是React,在编译之后返回的都是VNode

双缓存机制

一方面,React在拿到编译之后的VNode,首先会在内存中和上次更新的VNode进行对比,找到具体更新的VNode并且在内存中更新,上次没有更新时(mount),在内存中全部更新。


然后将VNode渲染在真实Dom里,使用current属性连接,同时保留内存中的VNode,使用altername属性使每个真实Dom对应,以方便下次更新时对比。

这个机制叫做双缓存机制另一方面,React被重新设计为可以中断的更新UI,这么做的好处是可以避免因为高复杂度的更新因为耗时长使用户感知到页面的卡顿。

Firbe架构

这种可中断的更新架构就是Firbe架构。

可以中断的更新原理是:如果浏览器计算和渲染的时间超过人眼可以感知卡顿的最短时间16.6ms,那就中断它,把时间让给下一个更新任务。等时间充裕的时候再重新更新。

其他的手段

React还将一些优化的任务交给了开发者,比如,前面说过,jsx是动态的,如果你的组件全是不会变化的,那么你可以使用React.meno()包裹你的组件,明确这是个静态的,以此来较少无用的更新。还有useStateuseMemouseCallback等。

相关文章
|
1月前
|
前端开发 JavaScript 开发者
颠覆传统:React框架如何引领前端开发的革命性变革
【10月更文挑战第32天】本文以问答形式探讨了React框架的特性和应用。React是一款由Facebook推出的JavaScript库,以其虚拟DOM机制和组件化设计,成为构建高性能单页面应用的理想选择。文章介绍了如何开始一个React项目、组件化思想的体现、性能优化方法、表单处理及路由实现等内容,帮助开发者更好地理解和使用React。
77 9
|
25天前
|
监控 前端开发 数据可视化
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
@icraft/player-react 是 iCraft Editor 推出的 React 组件库,旨在简化3D数字孪生场景的前端集成。它支持零配置快速接入、自定义插件、丰富的事件和方法、动画控制及实时数据接入,帮助开发者轻松实现3D场景与React项目的无缝融合。
94 8
3D架构图软件 iCraft Editor 正式发布 @icraft/player-react 前端组件, 轻松嵌入3D架构图到您的项目,实现数字孪生
|
28天前
|
前端开发 JavaScript 开发者
使用React和Redux构建高效的前端应用
使用React和Redux构建高效的前端应用
33 1
|
1月前
|
前端开发 JavaScript Android开发
前端框架趋势:React Native在跨平台开发中的优势与挑战
【10月更文挑战第27天】React Native 是跨平台开发领域的佼佼者,凭借其独特的跨平台能力和高效的开发体验,成为许多开发者的首选。本文探讨了 React Native 的优势与挑战,包括跨平台开发能力、原生组件渲染、性能优化及调试复杂性等问题,并通过代码示例展示了其实际应用。
63 2
|
1月前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
35 2
|
1月前
|
前端开发 JavaScript 数据管理
React与Vue:两大前端框架的较量与选择策略
【10月更文挑战第23天】React与Vue:两大前端框架的较量与选择策略
|
23天前
|
前端开发 JavaScript 算法
探索现代前端框架——React 的性能优化策略
探索现代前端框架——React 的性能优化策略
20 0
|
23天前
|
前端开发 JavaScript API
探索现代前端框架——React 的性能优化策略
探索现代前端框架——React 的性能优化策略
26 0
|
1月前
|
前端开发 Android开发 开发者
前端框架趋势:React Native在跨平台开发中的优势与挑战
【10月更文挑战第26天】近年来,React Native凭借其跨平台开发能力在移动应用开发领域迅速崛起。本文将探讨React Native的优势与挑战,并通过示例代码展示其应用实践。React Native允许开发者使用同一套代码库同时构建iOS和Android应用,提高开发效率,降低维护成本。它具备接近原生应用的性能和用户体验,但也面临平台差异、原生功能支持和第三方库兼容性等挑战。
43 0
|
7月前
|
设计模式 前端开发 数据可视化
【第4期】一文了解React UI 组件库
【第4期】一文了解React UI 组件库
381 0