SolidJS walkthrough 02 - Types in SolidJS
Saturday, Apr 08, 2023
SolidJS 内的数据结构
SignalState
当我们调用 createSignal,在其内部就创建了一个 SignalState 类型的对象,SignalState 就是响应式的数据源,当 SignalState 更新后会触发其观察者更新或者副作用的触发。
见下方 TS 类型 SignalState
:
export interface SourceMapValue {
value: unknown
name?: string
graph?: Owner
}
export interface SignalState<T> extends SourceMapValue {
value: T
observers: Computation<any>[] | null
observerSlots: number[] | null
tValue?: T
comparator?: (prev: T, next: T) => boolean
}
主要的 property:
- value:当前 Signal 的值
- observers:当前 Signal 的 observer(比如 Effect、Memo),当 signal 的 value 更新之后,observer 会被触发执行
- observerSlots: 当前 Signal 在对应 observer 的 sources 的位置(下面会讲到
Computation
这个类型) - tValue: Transition 下临时保存待更新的值(暂不考虑 Transition)
Computation
createEffect、createMemo、createComputed、createReaction 内部都会创建一个 Computation 对象,Computation 对象就是响应式的观察者,当 SignalState 更新后,Computation 对象会触发更新或者副作用的执行。
export interface Computation<Init, Next extends Init = Init> extends Owner {
fn: EffectFunction<Init, Next>
state: ComputationState
tState?: ComputationState
sources: SignalState<Next>[] | null
sourceSlots: number[] | null
value?: Init
updatedAt: number | null
pure: boolean
user?: boolean
suspense?: SuspenseContextType
}
主要的几个属性:
- fn:当前 Computation 保存的函数,在观察的 signal 变化的时候会触发 fn 的重新执行
- state:当前 Computation 保存的状态,state 有 0、1、2。 1 代表 STALE,表示当前 Computation 已经过期需要重新计算最新的值,2 代表 PENDING,表示当前 Computation 需要等待其他值更新完毕之后再做更新计算
- tState:和 Transition 相关的 state(先不考虑)
- sources:当前 Computation 关联的所有 signal
- sourceSlots:当前 Computation 在对应的 signal 的 observers 数组中的位置
- pure:当前 Computation 是否涉及副作用,(Memo 的 pure 为 true,effect 为 false),pure 值会影响到在更新时该 Computation 的执行时机是在 Updates 数组中还是在 Effects 数组中。
Owner
从上面可以看到 Computation 是 extends 于 Owner 这个类型的,很多场景下 Computation 就是当前上下文的 Owner,Owner 保存着当前上下文(or 作用阈?)内的一些信息,比如 onCleanUp 函数、ErrorBoundary 函数等等。
Owners 构成了一棵树,由 owner 属性关联其父节点的 owner,owned 数组保存其子 owner 节点。其主要作用是帮助 SolidJS 建立 组件粒度,使得生命周期、ErrorBoundary 可以存在(个人的粗浅理解,可能不准确)。
export interface Owner {
owned: Computation<any>[] | null
cleanups: (() => void)[] | null
owner: Owner | null
context: any | null
sourceMap?: SourceMapValue[]
name?: string
}
Memo
Memo 其实是一个 Signal + Computation 的结合,它本身是一个可以拿去使用的值,但是它又依赖了其他 SignalState,当其依赖的 State 更新之后,Memo 本身也会更新,从类型定义也可以看出来:
export interface Memo<Prev, Next = Prev> extends SignalState<Next>, Computation<Next> {
value: Next
tOwned?: Computation<Prev | Next, Next>[]
}