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方法实现依赖收集和派发更新功能。

相关推荐
jiayong233 分钟前
Vue2 与 Vue3 常见面试题精选 - 综合宝典
前端·vue.js·面试
We་ct11 分钟前
LeetCode 383. 赎金信:解题思路+代码解析+优化实战
前端·算法·leetcode·typescript
东东51619 分钟前
OA自动化居家办公管理系统 ssm+vue
java·前端·vue.js·后端·毕业设计·毕设
周某人姓周23 分钟前
DOM型XSS案例
前端·安全·web安全·网络安全·xss
程序员鱼皮34 分钟前
前特斯拉 AI 总监:AI 编程最大的谎言,是 “提效”
前端·后端·ai·程序员·开发
pusheng20251 小时前
普晟传感2026年新春年会总结与分析
前端·javascript·html
谢尔登1 小时前
React19事件调度的设计思路
前端·javascript·react.js
Emma_Maria1 小时前
本地项目html和jquery,访问地址报跨域解决
前端·html·jquery
奋斗吧程序媛1 小时前
常用且好用的命令
前端·编辑器
2301_796512521 小时前
【精通篇】打造React Native鸿蒙跨平台开发高级复合组件库开发系列:Lazyload 懒加载(懒加载的图片)
前端·javascript·react native·react.js·ecmascript·harmonyos