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> = () => Ttype 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)
如果你想在 Signal 中存储一个函数,你必须使用函数形式:
setValue(() => myFunction);
但是,函数在作为 initialValue
参数传给 createSignal
时不会被特殊对待,所以你可以直接传递函数作为初始值:
const [func, setFunc] = createSignal(myFunction);
选项
名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
equals | false | ((prev: T, next: T) => boolean) | === | 一个用于判断 Signal 的值是否改变的函数。如果函数返回 true,Signal 的值不会更新且依赖不会重新运行。如果函数返回 false,Signal 的值会更新且依赖会重新运行。 |
name | string | Signal 的名称。这对调试很有用。 | |
internal | boolean | false | 如果为 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 })