preact原理解析

一. preact介绍

preact是前端框架,开发体验与React相似,使用JSX语法,提供与React相同的API。本文主要解析preactreact的渲染流程差和preactsignals机制。

preact使用示例

javascript 复制代码
import { render } from 'preact'
import { useState } from 'preact/hooks'

function App() {
  const [counter, setCounter] = useState(0)
  
  return (
    <div>
      <h1 onClick={() => setCounter(counter + 1)}>{counter}</h1>
    </div>
  )
}

render(<App />, document.querySelector('#app'))

二. preact渲染流程

preact渲染流程中使用了虚拟DOM树,虚拟DOM树的节点会维护对应真实DOM节点。

在首次渲染中,会采用深度优先遍历算法递归创建虚拟DOM节点,且同时创建其对应的真实DOM节点,然后会将真实DOM节点插入到父DOM节点中,当整个虚拟DOM树构建完成后,会将创建好真实DOM树插入到页面指定节点上完成首次渲染流程。

当状态更新时,会触发更新渲染,与React不同的是,preact不会重新创建新的虚拟DOM树,而是从触发状态更新的虚拟DOM节点开始进行diff,创建其对应的新的虚拟DOM节点,然后更新到当前虚拟DOM树中,也就是preact的更新颗粒度相比React会更细,可以做到局部更新。需要注意的是更新时机和React一样都是异步的。

三. preact signals

preact中如果要使用signals,如果要额外引入@preact/signals依赖。

preact signals使用示例如下,从示例中可以发现获取/修改状态的方式与React有比较大的差异,更贴合Vue的使用方式。

javascript 复制代码
import { render } from 'preact'
import { useSignal } from '@preact/signals'

function App() {
  const counter = useSignal(0)

  return (
    <div>
      <h1 onClick={() => counter.value++}>{counter.value}</h1>
    </div>
  )
}

render(<App />, document.querySelector('#app'))

3.1 实现useSignal

useSignalpreact提供的hook方法,底层调用signal方法创建Signal对象。

javascript 复制代码
import { signal } from '@preact/signals'
import { useMemo } from 'preact/hooks'

export function useSignal(value) {
  return useMemo(() => signal(value), [])
}

3.2 实现signals

核心逻辑是通过Object.defineProperty方法添加Signal对象value属性的getset拦截器(和Vue2的响应式更新实现理念很类似)。具体执行逻辑如下:

  • 定义Signal对象,添加value属性的getset拦截器
  • 创建Signal对象实例,记录初始值
  • 当访问Signal对象实例的value属性时,会收集当前虚拟DOM节点的触发更新渲染方法
  • 当修改Signal对象实例的value属性时,触发当前虚拟DOM节点的更新渲染方法

3.2.1 定义Signal对象

javascript 复制代码
function Signal(value) {
  // 记录value属性值
  this._value = value
  // 记录虚拟DOM节点的更新渲染方法
  this._targets = null
}

Object.defineProperty(Signal.prototype, 'value', {
  get(signal) {
    // 该方法核心逻辑是收集虚拟DOM节点的更新渲染方法
    addDependency(signal)
    return signal._value
  },
  set(signal, value) {
    if (value !== signal._value) {
      signal._value = value
      // 触发更新渲染
      signal._targets._notify()
    }
  },
})

3.2.2 定义signal方法

javascript 复制代码
function signal(value) {
  return new Signal(value)
}

四. 总结

React一样,preact渲染流程也使用了虚拟DOM树,不同点在于更新渲染时preact不会重新构建一颗完整的虚拟DOM树,而是使用了局部更新机制。

preact signals的核心实现逻辑与Vue2很类似,主要是使用到Object.defineProperty方法实现依赖收集和派发更新功能。

相关推荐
Lee川1 小时前
Milvus 实战:当 RAG 遇上向量数据库,从"玩具 Demo"到"生产可用的"那一步
前端·数据库·人工智能
anOnion2 小时前
构建无障碍组件之Toolbar Pattern
前端·html·交互设计
惊鸿一博2 小时前
图标加载方式_zeroIcon_是否加前缀mdi
开发语言·前端·javascript
2501_940041742 小时前
前端工程化进阶:5个高交互与可视化项目提示词
前端
你很易烊千玺2 小时前
JS 异步 从零讲(大白话 + 真实场景 + 可运行案例)
前端·javascript·vue.js
华洛4 小时前
讲讲如何在传统产品中挖掘AI需求
javascript·产品经理·产品
why技术4 小时前
AI Coding开始进入第四个时代,我还没上车呢!
前端·人工智能·后端
大家的林语冰5 小时前
CSS 已死?DOM 性能黑洞!Pretext 排版革命让你在文本间跳舞,没有 DOM 也能纵享丝滑~
前端·javascript·css
vipbic5 小时前
我也该升级了,陪伴了我7年的博客
前端
Lee川5 小时前
RAG 实战:从一篇掘金文章出发,拆解检索增强生成的全链路
前端·人工智能·后端