前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >谈谈我对 Reacitive 方法的理解

谈谈我对 Reacitive 方法的理解

作者头像
前端修罗场
发布2023-10-31 08:27:27
1690
发布2023-10-31 08:27:27
举报
文章被收录于专栏:Web 技术Web 技术

本文我想和大家分享一下我对当前 Reactivity 方法和现状的理解。我并不是说我的观点就是对的,但我认为,正是通过分享自己的观点,我们才能对行业中的事物达成共识,我希望这些来之不易的见解能够对其他人有所帮助,并补充他们理解中缺失的部分。

reacitve 三剑客

我认为到目前为止,我们在行业中看到的 reacitive 方法有三种:

  1. 基于 value:也就是脏检查,应用的框架有 Angular, React, Svelte;
  2. 基于 observable : 应用的框架有 Angular with RxJS, Svelte;
  3. 基于 singnal:应用的框架有 Angular with signals, Qwik, React with MobX, Solid, Vue

接下来我来谈谈这三种方法:

基于 value

基于 value 的系统依赖于将状态作为简单值存储在“不可观察”引用中。

当我 说“observable” 时,我并不是指的是像 RxJS 这样的可观察对象。我指的是“可观察”这个词的常用用法,比如知道它什么时候发生了变化。“不可观察”意味着当值发生变化时,没有办法及时知道具体的实例。下面我给出三个例子:

  • React
代码语言:javascript
复制
function Counter() {
  const [count, setCount] = useState(0)
  return <button onClick={() => setCount(count + 1)}>{count}</button>
}
  • Angular
代码语言:javascript
复制
import { Component } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `
    <h1>Counter: {{ count }}</h1>
    <button (click)="increment()">Increment</button>
  `,
})
export class CounterComponent {
  count: number = 0;

  increment() {
    this.count++;
  }
}
  • Svelte
代码语言:javascript
复制
<script>
  let count = 0;

  function increment() {
    count += 1;
  }
</script>

<div>
  <h1>Counter: {count}</h1>
  <button on:click={increment}>Increment</button>
</div>

在上面的每种情况下,状态都作为一个值存储在变量中。但关键是它是一个不可观察的值,以一种不允许框架知道(观察)值何时变化的方式存储在 JavaScript 中。

由于该值的存储方式不允许框架观察到变化,因此每个框架都需要一种方法来检测这些值何时发生变化,并将组件标记为脏组件。

一旦标记为 dirty,就会重新运行组件,以便框架可以重新读取/重新创建值,从而检测哪些部分发生了更改,并将更改反映到 DOM。

脏检查是基于 value 的系统所能采用的唯一策略。它将最后一个已知值与当前值进行比较

那怎么知道什么时候运行脏检查算法呢?通常不同的框架方式不同:

  • Angular: 隐式依赖 zone.js 来检测状态何时可能发生了变化。(因为它依赖于通过zone.js 的隐式检测,所以运行变更检测的频率比严格必要的要高。)
  • React: 显式依赖于开发人员调用 setState()
  • Svelte: 自动生成 setState() 调用

基于 Observable

Observable 对象是随时间变化的值。Observable 对象允许框架在值发生变化时及时知道具体的实例,因为将新值推送到 Observable 对象中需要特定的 API 来充当保护。

可观察对象是解决细颗粒 Reacitive 问题的明显方法。但是,因为 observable 需要显式调用 .subscribe() 和相应的调用 .unsubscribe(),导致开发体验不好 。可观察对象也不能保证同步无故障的交付,UI 倾向于同步更新。下面我们给出代码示例:

  • Angular
代码语言:javascript
复制
import { Component } from '@angular/core';
import { Observable, BehaviorSubject } from 'rxjs';

@Component({
  selector: 'app-counter',
  template: `
    <h1>Counter: {{ count$ | async }}</h1>
    <button (click)="increment()">Increment</button>
  `,
})
export class CounterComponent {
  private countSubject = new BehaviorSubject<number>(0);
  count$: Observable<number> = this.countSubject.asObservable();

  increment() {
    this.countSubject.next(this.countSubject.value + 1);
  }
}
  • Svelte
代码语言:javascript
复制
<script>
  import { writable } from 'svelte/store';

  const count = writable(0);

  function increment() {
    // Update the count by incrementing it
    count.update(n => n + 1);
  }
</script>

<div>
  <h1>Counter: {$count}</h1>
  <button on:click={increment}>Increment</button>
</div>

Svelte: 有趣的是,它有两个具有不同心智模型和语法的 Reacitive 系统。这是因为基于value 的模型只在 .svelte 文件中工作,所以将代码移出 .svelte 文件需要一些其他的 Reacitive 原语(Stores)。

我相信每个框架都应该有一个可以处理所有用例的单一 Reacitive 模型,而不是基于用例的不同 Reacitive 系统的组合。

基于 Signal

Signal 就像可观察对象的同步表兄弟没有订阅/取消订阅。我相信这是一个重大的编码改进,我也相信 Signal 是未来。

Signal 的实现并不明显,这就是为什么行业花了这么长时间才走到这一步。Signal 需要与底层框架紧密耦合,以获得最佳的编码体验和性能。

为了获得最好的结果,需要协调框架渲染和可观察对象更新。下面给出几个示例:

  • Qwik
代码语言:javascript
复制
export const Counter = component$(() => {
  const count = useSignal(123);
  return (
    <button onClick$={() => count.value++}>
      {count.value}
    </button>
  );
});
  • SolidJS
代码语言:javascript
复制
export const Counter = (() => {
  const [count, setCount] = createSignal(123);
  return (
    <button onClick={() => setCount(count() + 1)}>
      {count()}
    </button>
  );
});
  • Vue
代码语言:javascript
复制
<template>
  <section>
    <h1>Count: {{ count }}</h1>
    <button @click="incrementCount">+1</button>
  </section>
</template>

<script setup>
import { ref } from 'vue';

const count = ref(0);
function incrementCount() {
  count.value++;
}
</script>

Angular 正在研究 Signal ,但它们仍然需要 Signal 和模板的集成。

最后,总结一下我的观点。

可观察对象太复杂了,不太适合。因为只有 BehaviorSubject 可观察对象才能真正与 UI 一起工作。

在基于 Value 的系统中,性能又是极其消耗的。虽然值的变化不会破坏应用程序,只是当有一天你觉它太慢了的时候,并且当你想要进行优化它时,就会发现没有“明显”的东西需要修复。

对于基于 Signal 的系统,对于开发者,最初的理解门槛会稍微高一些,并且开发者很有可能从 Reacitive 悬崖上掉下来。因为如果你对 Signal 的反应错误,应用程序就会崩溃。但是解决问题的办法也会很明显。

其次,当一旦你开始优化基于 Value 的系统的时候,你就会开始接触到基于 Signal 的世界,在那里你可能会像处理 Signal 一样失去 Reacitive。本质上,基于 Value 的“优化”API是“低于标准的 Signal 的”。

这也是我喜欢 Signal 的第二个原因。Signal 开启了一种很酷的编码方式,它允许你可视化系统的响应式并调试它。

好啦,以上就是我的理解,希望对你有帮助!

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-10-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • reacitve 三剑客
    • 基于 value
      • 基于 Observable
        • 基于 Signal
        相关产品与服务
        对象存储
        对象存储(Cloud Object Storage,COS)是由腾讯云推出的无目录层次结构、无数据格式限制,可容纳海量数据且支持 HTTP/HTTPS 协议访问的分布式存储服务。腾讯云 COS 的存储桶空间无容量上限,无需分区管理,适用于 CDN 数据分发、数据万象处理或大数据计算与分析的数据湖等多种场景。
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
        http://www.vxiaotou.com