状态管理是指处理和操作数据进而影响 Web 应用程序的行为和展示的过程。为了构建交互式和动态 Web 应用程序,状态管理是开发的一个重要方面。在 Solid 中,状态管理是通过使用响应式原语(reactive primitives)来帮助实现的。
让我们使用一个基础的计数器例子来展示这些状态管理概念:
状态管理有 3 个要素:
- 状态(State) (
count
): 决定向用户展示什么内容的数据。
- 视图(View) (
<div>{count()}</div>
): 向用户展示的状态的视觉表示。
- 交互(Actions) (
increment
): 任何修改状态的事件。
这些元素共同创建了“单向数据流”。当交互修改状态时,视图会更新以展示当前状态。数据流简化了数据和用户交互的管理过程,从而提供了更具可预测性和可维护的应用程序。
状态是应用程序的真实来源,用于确定向用户显示哪些内容。状态由 signal 表示,它是一个响应式原语,用于管理状态并向 UI 通知任何更改。
要创建一段状态,您可以使用 createSignal 函数并传入状态的初始值:
要访问状态的当前值,可以调用 signal 的 getter 函数:
要更新状态,您可以使用 signal 的 setter 函数:
通过 signal,您可以以简单直接的方式创建和管理状态。这使您可以专注于应用程序的逻辑,而不是状态管理的复杂性。此外,signal 是响应式的,这意味着只要在跟踪作用域内访问它,它就始终是最新的。
要实现动态用户界面,UI 必须能够反映数据的当前状态。 UI 是用户状态的直观表示,并使用 JSX 进行渲染。 JSX 提供了一个跟踪作用域,使视图与状态保持同步。
重新访问前面介绍的 Counter
组件,使用 JSX 在返回内容中渲染 count
的当前状态:
为了渲染 count
的当前状态,使用 JSX 表达式 {count()}
。大括号表示该表达式是 JavaScript 表达式,圆括号表示它是函数调用。该表达式代表 count
的 getter 函数,将获取当前状态值。当状态更新时,UI 将重新渲染以反映新的状态值。
Solid 中的组件在初始化时仅运行一次。在初始渲染之后,如果对状态进行任何更改,则只会更新与 signal 更改直接关联的 DOM 部分。
仅更新 DOM 相关部分的能力是 Solid 的一项关键功能,可实现高性能且高效的 UI 更新。这称为细粒度响应式。通过减少整个组件或更大 DOM 范围的重新渲染,UI 将保持更加高效和及时响应。
当状态更新时,任何更新都会反映在 UI 中。但是,有时您可能希望在状态更改时执行其他操作。
例如,在 Counter
组件中,您可能希望向用户显示 count
的双倍值。这可以通过使用 effects 来实现,effects
也是响应式原语,在状态改变时执行副作用:
createEffect
设置一个函数,用于在状态修改时执行副作用。这里,副作用是指由状态更改触发的、影响本地环境之外的状态的操作或更新,例如修改全局变量或更新 DOM。
在 Counter
组件中,只要 count
状态发生变化,就可以使用 createEffect
函数来更新 doubleCount
状态。这使 doubleCount
状态与 count
状态保持同步,并通过 UI 向用户显示 count
的双倍值。
查看 Solid Playground 示例中 createEffect 中 doubleCount 的示例。
当您想要根据现有状态值计算新的状态值时,可以使用派生状态。当您想要向用户显示状态值的转换,但不想修改原始状态值或创建新的状态值时,这是一个有用的模式。
可以使用函数内的 signal 创建派生值,该 signal 可以称为派生 signal 。
这种方法可用于简化上面的 doubleCount
示例,其中额外的 signal 和 effect 可以用派生 signal 替换:
此方法适用于简单的用例,但如果 doubleCount
在组件内多次使用或包含计算量大的计算,则可能会导致性能问题。
不仅每次 count
更改时,而且每次使用 doubleCount()
时,都会重新评估派生 signal 。
此方法适用于简单的用例,但如果 doubleCount
在组件内多次使用或包含计算量大的计算,则可能会导致性能问题。
不仅每次 count
更改时,而且每次使用 doubleCount()
时,都会重新评估派生 signal 。
多次访问时,doubleCountMemo
仅重新评估并记录一次。这与派生 signal doubleCount
不同,派生 signal 在每次访问时都会重新评估。
查看 Solid Playground 中比较派生 signal 和 memo 的类似示例。
当您想要在组件之间共享状态时,可以将状态提升到共同的祖先组件。虽然状态不与组件绑定,但您可能希望将多个组件链接在一起,以便访问和操作同一个状态。这可以使整个组件树保持同步,实现更可预测的状态管理。
例如,在 Counter
组件中,您可能希望通过单独的组件向用户显示 count
的双倍值:
要在 Counter
和 DisplayCounts
组件之间共享 count
状态,您可以将状态提升到 App
组件。这允许 Counter
和 DisplayCounts
函数访问同一状态,也允许 Counter
组件通过 setCount
setter 函数更新状态。
当组件之间共享状态时,可以通过 ∑ 访问状态。从父组件传递下来的 props 值是只读的,这意味着子组件不能直接修改它们。但是,您可以从父组件传递 setter 函数,以允许子组件间接修改父组件的状态。
Info: 为了鼓励单向数据流,props 作为只读或不可变值从父组件传递到子组件。
然而,props 有特定的工具函数,提供修改 props 值的方法。
随着应用程序规模和复杂性的增加,提升状态可能变得难以管理。为了避免 prop drilling 的概念(即通过多个组件传递 props 的过程),Solid 提供 stores 以更具可扩展性和可维护性的方式管理状态。
要了解有关管理复杂状态的更多信息,请导航至复杂状态管理页面。