preact原理解析

一. preact介绍

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

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

useSignal是preact提供的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属性的get和set拦截器(和Vue2的响应式更新实现理念很类似)。具体执行逻辑如下:

  • 定义Signal对象,添加value属性的get和set拦截器
  • 创建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方法实现依赖收集和派发更新功能。

相关推荐
IT_陈寒16 小时前
Redis大key删除为什么会导致服务卡顿?我的线上事故复盘
前端·人工智能·后端
系统集成-鹰翔16 小时前
ERP图片改名后仍命中识别缓存:缓存键、十分钟到期与调用计数
javascript·经验分享·后端
用户27050777252417 小时前
MCP 最小 Server 实测:3 个 JSON-RPC 报错与修法
前端
用户4993350250717 小时前
一人VIP账号多人共用:Web 代理里的会话共享怎么实现
前端
用户老李17 小时前
无线电自学教程 05:第一台收音机——从矿石机到 SDR
前端
IPIPD17 小时前
Node.js请求遇到503怎么重试?先解析Retry-After,再做有上限退避
前端
葡萄城技术团队17 小时前
dsh-spreadjs-editor 的集成链路:把 SpreadJS Designer 嵌进 Agent 工作台
前端
FlyWIHTSKY18 小时前
vue2和vue3有什么区别,用法上有哪些区别
前端·javascript·vue.js
码云之上18 小时前
10 颗一模一样的「Edit」:中后台 Web Agent 怎么找到对的那一行
前端·人工智能·浏览器
量化分析码农19 小时前
【Python量化多因子实战 04】因子暴露不是 alpha:市值与行业中性化实战
前端·后端