Basic Reactivity

createSignal

编辑此页面

Signals 是最基本的响应式原语。 它们可以追踪一个随时间变化的单一值(可以是任何 JavaScript 对象)。

import { createSignal } from "solid-js"
function createSignal<T>(
initialValue: T,
options?: {
equals?: false | ((prev: T, next: T) => boolean)
name?: string
internal?: boolean
}
): [get: () => T, set: (v: T) => T]
// createSignal 返回值的可用类型:
import type { Signal, Accessor, Setter } from "solid-js"
type Signal<T> = [get: Accessor<T>, set: Setter<T>]
type Accessor<T> = () => T
type Setter<T> = (v: T | ((prev?: T) => T)) => T

Signal 的值初始化为传入的第一个参数 initialValue(如果没有参数则为 undefined)。 createSignal 函数返回一个包含两个函数的数组:一个 getter(访问器)和一个 setter。 在典型用法中,你会将这个数组解构为一个命名的 Signal,像这样:

const [count, setCount] = createSignal(0)
const [ready, setReady] = createSignal(false)

调用 getter(例如 count()ready())会返回 Signal 的当前值。

对于自动依赖追踪来说很重要的是,在追踪作用域内调用 getter 会使调用函数依赖于这个 Signal,所以当 Signal 更新时这个函数会重新运行。

调用 setter(例如 setCount(nextCount)setReady(nextReady))会设置 Signal 的值,如果值确实发生改变则更新 Signal(触发依赖重新运行)(详见下文)。 setter 接收一个参数,可以是 signal 的新值,也可以是一个将 signal 的上一个值映射为新值的函数。 setter 也会返回更新后的值。例如:

// 读取 signal 的当前值,并且
// 如果在追踪作用域内则依赖于该 signal
// (但在追踪作用域外是非响应式的):
const currentCount = count()
// 或者用函数包装任何计算,
// 这个函数可以在追踪作用域中使用:
const doubledCount = () => 2 * count()
// 或者构建一个追踪作用域并依赖 signal:
const countDisplay = <div>{count()}</div>
// 通过提供一个值来写入 signal:
setReady(true)
// 通过提供一个函数 setter 来写入 signal:
const newCount = setCount((prev) => prev + 1)

选项

名称类型默认值描述
equalsfalse | ((prev: T, next: T) => boolean)===一个用于判断 Signal 的值是否改变的函数。如果函数返回 true,Signal 的值不会更新且依赖不会重新运行。如果函数返回 false,Signal 的值会更新且依赖会重新运行。
namestringSignal 的名称。这对调试很有用。
internalbooleanfalse如果为 true,Signal 在开发工具中将不可访问。

equals

equals 选项可用于自定义判断 Signal 值是否改变的相等性检查。 默认情况下,相等性检查使用严格相等(===)。 如果你想使用不同的相等性检查,你可以传入一个自定义函数作为 equals 选项。 这个自定义函数将接收 Signal 的前一个值和下一个值作为参数。 如果函数返回 true,Signal 的值不会更新且依赖不会重新运行。 如果函数返回 false,Signal 的值会更新且依赖会重新运行。

const [count, setCount] = createSignal(0, {
equals: (prev, next) => prev === next,
})

这里有一些使用该选项的例子:

// 使用 { equals: false } 允许就地修改对象;
// 通常这不会被视为更新,因为对象前后具有相同的标识
const [object, setObject] = createSignal({ count: 0 }, { equals: false })
setObject((current) => {
current.count += 1
current.updated = new Date()
return current
})
// 使用 { equals: false } signal 作为无值的触发器:
const [depend, rerun] = createSignal(undefined, { equals: false })
// 现在在追踪作用域中调用 depend()
// 会使该作用域在每次调用 rerun() 时重新运行
// 基于字符串长度定义相等性:
const [myString, setMyString] = createSignal("string", {
equals: (newVal, oldVal) => newVal.length === oldVal.length,
})
setMyString("string") // 被视为与上一个值相等,不会触发更新
setMyString("stranger") // 被视为不同,会触发更新

name

name 选项可用于给 Signal 一个名称。 这对调试很有用。该名称会在开发工具中显示。

const [count, setCount] = createSignal(0, { name: "count" })

internal

internal 选项可用于在开发工具中隐藏 Signal。 这对于组件内部使用且不应暴露给用户的 Signal 很有用。

const [count, setCount] = createSignal(0, { internal: true })
报告此页面问题