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

相关推荐
Csvn4 分钟前
structuredClone:原生深拷贝 API 的正确打开方式
前端
大猫会长9 分钟前
获取favicon.ico的方法
前端·javascript·html
无人生还9 分钟前
从 Vue3 到 React · 快速上手系列第 5 篇:事件处理与表单(受控组件 vs v-model)
前端·vue.js·react.js
默_笙13 分钟前
🎀 大模型说"呀"还是"吗"?temperature 和 Top K 在偷偷控制它的"性格"
前端·javascript
渣波13 分钟前
别再死磕MySQL了!用Milvus+LangChain给AI加个“海马体”,手把手带你写个RAG日记本
前端
乌夷16 分钟前
vue知识点
前端·javascript·vue.js
何时梦醒22 分钟前
🚀 从零上手 Milvus 向量数据库:打造一个 AI 智能日记本
前端·人工智能
blns_yxl24 分钟前
拖拽排序列表(HTML+JS)
前端·javascript·html
Data25 分钟前
把 React 前端做成「插件市场」:前后端联动的行业包可插拔架构
前端
光影少年27 分钟前
RN Bridge 原理
前端·react native·react.js