将信号引入 Lit Labs
新的 Signals 包将 TC39 Signals 提案与 Lit 集成在一起
宣布 @lit-labs/signals: 将 TC39 Signals 提案与 Lit 集成
我们很高兴宣布发布我们最新的 Lit Labs 包,@lit-labs/signals
,它将激动人心的新TC39 Signals 提案 的polyfill 与 Lit 直接集成在一起。该包通过允许您使用共享的、可观察的信号,提供了一种强大且响应式的方式来管理 Web 应用程序中的状态,这些信号在它们的值发生变化时会自动更新组件。
信号正在迅速成为 JavaScript 生态系统中的核心功能,而 TC39 提案有可能统一信号以及我们在各种库和框架中管理状态和响应性的方式。
尽管该提案仍处于早期阶段,但您可以立即开始尝试使用信号和 @lit-labs/signals
,看看在通用响应式原语上构建组件和应用程序对您来说是否可行。
什么是信号?
简而言之,信号是可观察的数据结构,它们保存值或计算结果。当信号的值发生变化时,依赖它的应用程序的所有组件或部分都会自动被通知并更新。这在 UI 中尤其有用,在 UI 中,多个组件可能需要共享状态并对状态的变化做出反应。
基于标准的信号的关键优势
- 共享可观察状态:信号非常适合管理跨多个组件共享的状态。如果一个组件更新了信号,所有其他使用该信号的组件也会自动更新。
- 精确更新:信号能够实现精确的目标重新渲染,这有可能通过仅处理其信号支持的值已更改的绑定来提高性能,从而跳过同一模板中的其他绑定。
- 互操作性:信号的标准化意味着不同的库和框架可以互操作地使用信号,从而减少对复杂适配器的需求并提高兼容性。
我们为何对 @lit-labs/signals
感到兴奋
Lit 以其构建 Web 组件的轻量级、高性能和声明性方法而闻名。但 Lit 严格专注于帮助您构建可重用、封装的组件。Lit 不是框架,它不会规定如何对您的数据进行建模或使其可观察。
Lit 的响应性在默认情况下是相对浅的。组件在它们自己的响应式属性发生变化时会自动更新,但在嵌套属性发生变化时不会更新。响应深度属性的变化,要么需要手动更新请求,要么需要集成像 Redux 或 MobX 这样的状态管理系统。
信号为我们提供了与这些状态管理系统相同的深度可观察性功能,但使用更小、更简单的 API,并且有可能成为大型生态系统中的通用标准,包括实用程序、组件和框架。
信号对 Lit 来说并非完全是新事物。我们之前发布过 @lit-labs/preact-signals
包,但我们对需要为特定信号库构建 Lit 集成,以及为 Lit 开发人员可能想要使用的每个信号库构建 Lit 集成,感到有些不满。
JavaScript 中的标准化信号将使我们能够仅构建一个集成(并最终在 Lit 的核心库中添加信号支持),并启用使用信号库之间的互操作性,这与 Web 组件启用的互操作性精神一致。
新的 @lit-labs/signals
包使从您的 Lit 组件中使用新的信号提案变得超级容易。
让我们深入研究几个示例...
示例 1:共享计数器
以下是一个使用 @lit-labs/signals
的共享计数器示例。为了在该组件中启用基于信号的响应性,我们只需在自定义元素定义中使用 SignalWatcher
mixin;我们读取的任何信号都会自动被观察,并在它们的值发生变化时触发更新
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';
import {SignalWatcher, signal} from '@lit-labs/signals';
// This is a standard TC39 signal that uses the signals polyfill.
// The signal is shared across all component instances.
const count = signal(0);
@customElement('shared-counter')
export class SharedCounterComponent extends SignalWatcher(LitElement) {
render() {
// Just by using the signal in your template, your component will update
// when the signal changes.
return html`
<p>The count is ${count.get()}</p>
<button @click=${this.increment}>Increment</button>
`;
}
increment() {
count.set(count.get() + 1);
}
}
使用这种方法,可以将任意数量的 <shared-counter>
组件添加到 DOM 中,所有组件都会反映相同的计数器值,并在信号发生变化时自动更新。
示例 2:精确 DOM 更新
使用 watch
指令,我们还可以实现精确更新,以针对单个绑定而不是整个组件
import {LitElement, html} from 'lit';
import {customElement} from 'lit/decorators.js';
import {SignalWatcher, watch, signal} from '@lit-labs/signals';
const count = signal(0);
@customElement('pinpoint-counter')
export class PinpointCounter extends SignalWatcher(LitElement) {
render() {
return html`
<p>The count is ${watch(count)}</p>
<button @click=${this.increment}>Increment</button>
`;
}
increment() {
count.set(count.get() + 1);
}
}
在这里,只有显示计数的绑定会在信号发生变化时被处理,从而跳过不必要的操作并提高性能。
未来工作
这仅仅是我们探索 Lit 的信号集成的开始。很快,我们将为 @lit-labs/signals
添加更多实用程序,以便从集合中增量渲染更改、轻松地在组件中运行副作用,以及使用信号进行响应式属性。
最终——随着提议的标准的进展以及我们在 Lit 中使用信号的经验的积累——信号很可能会成为核心库的一部分。
Lit 团队正在与 TC39 Signals 提案的倡导者紧密合作,以确保信号适用于 Lit、Web 组件和平常 DOM 使用案例。我们不能过分强调我们对信号的潜力,它可以形成一个跨库和组件工作的互操作响应式原语,而无需集中式框架。
尝试一下并提供反馈
我们渴望在您尝试使用这个新包时获得社区的反馈。作为 Lit Labs 家族的一部分,@lit-labs/signals
仍然是实验性的,可能会根据用户反馈和 TC39 Signals 提案的进展而发生重大变化。
要开始使用,只需安装该包
npm i @lit-labs/signals
我们很乐意听取您的想法,因此请尝试一下,并告诉我们它对您来说如何运作。
- 初步文档位于 lit.dev/docs/data/signals/
- 您可以在 GitHub 上分享关于反馈讨论 的反馈
- 在Lit monorepo issues 中报告问题
- 加入我们的Discord 服务器 聊天!
我们很高兴看到您将使用信号构建什么,以及它们将如何塑造 Web 应用程序中状态管理的未来!
谢谢!
- Lit 团队