Vue 3 = React + Signals(译)

大家好,这里是大家的林语冰。

免责声明

本文属于是语冰的直男翻译了属于是,仅供粉丝参考,英文原味版请临幸 React + Signals = Vue 3。

所有现代 JS(JavaScript)框架都在迅速采用 Signals(信号)。Signals 由来已久,但最近因为 Solidjs 带货焕发第二春,现在每个主流框架都在采用 Signals,包括但不限于 Qwik、Preact 和 Angular。Signals 可以显著减少样板(boilerplate),但无论底层框架如何,具体实现看起来或多或少难免趋同。举个栗子,一起来瞄一眼两个现在更流行的框架,React 和 Vue。

理解问题

JS 是一种非常强大的语言,但它不太适合响应式编程。为了演示这个问题,我们使用一个简单的代码片段:

js 复制代码
let a = 1
let b = 2

let c = a + b // 3

a += 1

console.log(c) // 3,但 a + b 现在实际上等于 4

这本质上是一大坨响应式库正试图解决的问题。

理解 Signals

Signals 是一种表示和管理状态的响应式方案。Signals 本质上是事件驱动的变量,可以被 App 的其他部分订阅。当 Signal 的值变化时,其所有订阅者都会收到通知,且它们的代码将重新运行。这赋能一种非常经济的方法来更新 UI 以响应状态更改。

用 SolidJs 编写的一个小例子浅显易懂:

js 复制代码
const [count, setCount] = createSignal(0)

// 设置 Signal 的初始值
count = 10

// 订阅 Signal 并打印当前值
count.subscribe(value => console.log(value))

// 更改 Signal 的值
setCount(20)

在 React 中使用 Signal(从 useState 到 Signals)

目前,要在 React 中管理组件间的状态,您需要通过 props 来传递它,创建若干 context 或使用类似 redux 的东东,这有自己的问题集和样板。

Preact 被标榜为轻快版 React,通过实现 Signal 正式首秀。

从本质上讲,Preact 中的 Signal 是一个具有保存值的 .value 属性的对象。该值可以更改,但 Signal 本身始终保持不变。

js 复制代码
import { signal } from '@preact/signals'

const count = signal(0)

// 通过读写 .value 来读取 Signal 的值:
console.log(count.value) // 0

// 更新 Signal 的值:
count.value += 1

// Signal 的值已更新:
console.log(count.value) // 1

在 Preact 中,当 Signal 作为 props 或 context 沿树向下传递时,我们只是传递对 Signal 本身的引用。这意味着,Signal 可以更新而无需重新渲染任何未订阅该 Signal 的组件。这是因为组件看到的是 Signal,而不是其值。

因此,Preact 可以跳过昂贵的渲染工作,只重新渲染实际需要更新的组件。

信号还有第二个重要特征:它们跟踪何时访问其值以及何时更新其值。这意味着,当您 .value 从组件内部访问信号时,如果信号的值自上次渲染组件以来发生了变化,Preact 将自动重新渲染该组件。这可确保 UI 始终反映应用程序的当前状态。

jsx 复制代码
import { signal } from '@preact/signals'

// 创建可被订阅的 Signal
const count = signal(0)

function Counter() {
  // 当组件变化时,在其中读写 .value 会自动重新渲染
  const value = count.value

  const increment = () => {
    // 通过给 .value 属性赋值更新 Signal:
    count.value++
  }

  return (
    <div>
      <p>Count: {value}</p>
      <button onClick={increment}>click me</button>
    </div>
  )
}

此外,可以使用 computed 函数组合多个 Signal。返回的计算 Signal 是只读的,当从回调函数中读写的任何 Signal 变化时,其值会自动更新。

jsx 复制代码
import { signal, computed } from '@preact/signals'

const todos = signal([
  { text: 'Buy groceries', completed: true },
  { text: 'Walk the dog', completed: false }
])

// 创建一个根据其他 Signal 计算得到的 Signal
const completed = computed(() => {
  // 当 todo 变化时,这里会回自动重新运行
  return todos.value.filter(todo => todo.completed).length
})

// 打印:1,因为一个 todo 被标记为完成
console.log(completed.value)

上述的所有内容都是用 Preact 编写的,但可以使用 signals-react 包并使用相同的语法直接转移到 React。

jsx 复制代码
// React 组件
import { signal } from '@preact/signals-react'

const count = signal(0)

function CounterValue() {
  // 只要 count Signal 更新
  // 我们就会为您自动重新渲染此组件
  return <p>Value: {count.value}</p>
}

Vue 中的 Signals

如果您是 Vue 爱好者,但并不熟悉 Signals,上述所有内容应该一目了然。代码看起来与 Vue 3 几乎相同。

这是因为响应性是 Vue 1 幕后的基本思想,甚至从版本 1 开始。Vue 中的相同代码如下所示:

js 复制代码
import { reactive, computed } from 'vue'

const todos = reactive([
  { text: 'Buy groceries', completed: false },
  { text: 'Walk the dog', completed: false }
])

const completed = computed(() => {
  return todos.filter(todo => todo.completed).length
})

todos[0].completed = true

console.log(completed.value)

此代码与诉诸 @preact/signals 编写的 React 代码"图灵等价"!

完结撒花

显而易见,代码看起来一毛一样。但这是一件坏事吗?Signals 肯定棒棒哒,这就是为什么所有主流框架都在迅速采用 Signals。

但归根结底,可维护的代码和良好的开发人体工程学是我们想要的,让所有框架都使用同款工具将产生协同效应,每个人都会从中受益。

此外,拥有在框架和不同代码库之间反复横跳的技能只会对某人的职业生涯有益。

友情赞助

您现在收看的是前端翻译计划,学废了的小伙伴可以订阅此专栏合集,我们每天佛系投稿,欢迎持续关注前端生态。谢谢大家的点赞,掰掰~

相关推荐
雪芽蓝域zzs2 小时前
第4节:el-select 弹窗事件控制(打开 / 关闭、选中事件、弹窗滚动事件)
vue.js·elementui
PYB32 小时前
【Web·JS·基础】函数的使用和展运算符...objs
前端·javascript
默_笙3 小时前
🚥 给 RAG 装一台心电监护仪:LangSmith 全链路观测(上)
前端·javascript
变与不变8064 小时前
js同步和异步难点重点详解
开发语言·javascript·ecmascript
Dovis(誓平步青云)5 小时前
多个链接不等于多份证据,新闻核验看板怎样合并来源
java·服务器·前端·javascript·人工智能·pdf·电脑
Dovis(誓平步青云)5 小时前
几个方案来回选不定?做一个随时切换的候选推荐页
android·java·服务器·开发语言·javascript·数据库·智能化
可乐鸡翅yeah_7 小时前
fmp4 碎片 MP4 格式 HLS 流,和传统 TS 分片有什么不一样
开发语言·javascript·ios·音视频·safari·m3u8·m3u8在线播放
ss2738 小时前
AI全栈实战 | 2.3-01 组件库实战:Element Plus 怎么搭出专业界面,过度封装为什么成维护负担
前端·javascript·elementui·vue
福兮说8 小时前
URL 编码的七个坑:c++ 传到后端变空格、%25 套娃、截断 emoji 直接报错
开发语言·前端·javascript·node.js·url
小的时候可菜了8 小时前
JS 异步的本质:从单线程到 thenable(一条进化链)
开发语言·前端·javascript