parent
7528d0fda4
commit
f3cea8ef0e
@ -1,17 +0,0 @@ |
|||||||
import { Computed as AlienComputed } from 'alien-signals'; |
|
||||||
|
|
||||||
export function computed<T>(getter: (cachedValue?: T) => T): Computed<T> { |
|
||||||
return new Computed<T>(getter); |
|
||||||
} |
|
||||||
|
|
||||||
export class Computed<T = any> extends AlienComputed { |
|
||||||
constructor(getter: (cachedValue?: T) => T) { |
|
||||||
super(getter); |
|
||||||
} |
|
||||||
get value(): T { |
|
||||||
return this.get(); |
|
||||||
} |
|
||||||
peek(): T { |
|
||||||
return this.currentValue; |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,3 @@ |
|||||||
|
export enum ReactiveFlags { |
||||||
|
IS_REFERENCE = '__v_isReference', |
||||||
|
} |
@ -0,0 +1,212 @@ |
|||||||
|
import { createReactiveSystem, Dependency, Link, Subscriber, SubscriberFlags } from 'alien-signals'; |
||||||
|
import { ReactiveFlags } from "./contents" |
||||||
|
const { |
||||||
|
link, |
||||||
|
propagate, |
||||||
|
endTracking, |
||||||
|
startTracking, |
||||||
|
updateDirtyFlag, |
||||||
|
processComputedUpdate, |
||||||
|
processEffectNotifications, |
||||||
|
} = createReactiveSystem({ |
||||||
|
updateComputed(computed: Computed) { |
||||||
|
return computed.update(); |
||||||
|
}, |
||||||
|
notifyEffect(effect: Effect) { |
||||||
|
effect.notify(); |
||||||
|
return true; |
||||||
|
}, |
||||||
|
}); |
||||||
|
|
||||||
|
let activeSub: Subscriber | undefined = undefined; |
||||||
|
let batchDepth = 0; |
||||||
|
|
||||||
|
export function startBatch(): void { |
||||||
|
++batchDepth; |
||||||
|
} |
||||||
|
|
||||||
|
export function endBatch(): void { |
||||||
|
if (!--batchDepth) { |
||||||
|
processEffectNotifications(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function signal<T>(): Signal<T | undefined>; |
||||||
|
export function signal<T>(oldValue: T): Signal<T>; |
||||||
|
export function signal<T>(oldValue?: T): Signal<T | undefined> { |
||||||
|
return new Signal(oldValue); |
||||||
|
} |
||||||
|
|
||||||
|
export class Signal<T = any> implements Dependency { |
||||||
|
public readonly [ReactiveFlags.IS_REFERENCE] = true |
||||||
|
// Dependency fields
|
||||||
|
subs: Link | undefined = undefined; |
||||||
|
subsTail: Link | undefined = undefined; |
||||||
|
|
||||||
|
constructor( |
||||||
|
public currentValue: T |
||||||
|
) { } |
||||||
|
|
||||||
|
get(): T { |
||||||
|
if (activeSub !== undefined) { |
||||||
|
link(this, activeSub); |
||||||
|
} |
||||||
|
return this.currentValue; |
||||||
|
} |
||||||
|
|
||||||
|
set(value: T): void { |
||||||
|
if (this.currentValue !== value) { |
||||||
|
this.currentValue = value; |
||||||
|
const subs = this.subs; |
||||||
|
if (subs !== undefined) { |
||||||
|
propagate(subs); |
||||||
|
if (!batchDepth) { |
||||||
|
processEffectNotifications(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
value(): T { |
||||||
|
return this.get(); |
||||||
|
} |
||||||
|
|
||||||
|
peek(): T { |
||||||
|
return this.currentValue; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function computed<T>(getter: () => T): Computed<T> { |
||||||
|
return new Computed<T>(getter); |
||||||
|
} |
||||||
|
|
||||||
|
export class Computed<T = any> implements Subscriber, Dependency { |
||||||
|
readonly [ReactiveFlags.IS_REFERENCE] = true |
||||||
|
currentValue: T | undefined = undefined; |
||||||
|
|
||||||
|
// Dependency fields
|
||||||
|
subs: Link | undefined = undefined; |
||||||
|
subsTail: Link | undefined = undefined; |
||||||
|
|
||||||
|
// Subscriber fields
|
||||||
|
deps: Link | undefined = undefined; |
||||||
|
depsTail: Link | undefined = undefined; |
||||||
|
flags: SubscriberFlags = SubscriberFlags.Computed | SubscriberFlags.Dirty; |
||||||
|
|
||||||
|
constructor( |
||||||
|
public getter: () => T |
||||||
|
) { } |
||||||
|
|
||||||
|
get(): T { |
||||||
|
const flags = this.flags; |
||||||
|
if (flags & (SubscriberFlags.PendingComputed | SubscriberFlags.Dirty)) { |
||||||
|
processComputedUpdate(this, flags); |
||||||
|
} |
||||||
|
if (activeSub !== undefined) { |
||||||
|
link(this, activeSub); |
||||||
|
} |
||||||
|
return this.currentValue!; |
||||||
|
} |
||||||
|
|
||||||
|
update(): boolean { |
||||||
|
const prevSub = activeSub; |
||||||
|
activeSub = this; |
||||||
|
startTracking(this); |
||||||
|
try { |
||||||
|
const oldValue = this.currentValue; |
||||||
|
const newValue = this.getter(); |
||||||
|
if (oldValue !== newValue) { |
||||||
|
this.currentValue = newValue; |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} finally { |
||||||
|
activeSub = prevSub; |
||||||
|
endTracking(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
peek(): T { |
||||||
|
return this.currentValue!; |
||||||
|
} |
||||||
|
|
||||||
|
value(): Readonly<T> { |
||||||
|
return this.get(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function effect<T>(fn: () => T): Effect<T> { |
||||||
|
const e = new Effect(fn); |
||||||
|
e.run(); |
||||||
|
return e; |
||||||
|
} |
||||||
|
|
||||||
|
export class Effect<T = any> implements Subscriber { |
||||||
|
readonly [ReactiveFlags.IS_REFERENCE] = true |
||||||
|
// Subscriber fields
|
||||||
|
deps: Link | undefined = undefined; |
||||||
|
depsTail: Link | undefined = undefined; |
||||||
|
flags: SubscriberFlags = SubscriberFlags.Effect; |
||||||
|
|
||||||
|
constructor( |
||||||
|
public fn: () => T |
||||||
|
) { } |
||||||
|
|
||||||
|
notify(): void { |
||||||
|
const flags = this.flags; |
||||||
|
if ( |
||||||
|
flags & SubscriberFlags.Dirty |
||||||
|
|| (flags & SubscriberFlags.PendingComputed && updateDirtyFlag(this, flags)) |
||||||
|
) { |
||||||
|
this.run(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
run(): T { |
||||||
|
const prevSub = activeSub; |
||||||
|
activeSub = this; |
||||||
|
startTracking(this); |
||||||
|
try { |
||||||
|
return this.fn(); |
||||||
|
} finally { |
||||||
|
activeSub = prevSub; |
||||||
|
endTracking(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
stop(): void { |
||||||
|
startTracking(this); |
||||||
|
endTracking(this); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function batch<T>(fn: () => T): T { |
||||||
|
startBatch(); |
||||||
|
try { |
||||||
|
return fn(); |
||||||
|
} finally { |
||||||
|
endBatch(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export function isSignal<T>(r: Signal<T> | unknown): r is Signal<T> |
||||||
|
export function isSignal(r: any): r is Signal { |
||||||
|
return r ? r[ReactiveFlags.IS_REFERENCE] === true : false |
||||||
|
} |
||||||
|
|
||||||
|
export type MaybeSignal<T = any> = |
||||||
|
| T |
||||||
|
| Signal<T> |
||||||
|
|
||||||
|
export type MaybeSignalOrGetter<T = any> = MaybeSignal<T> | Computed<T> | (() => T) |
||||||
|
|
||||||
|
export function unSignal<T>(signal: MaybeSignal<T> | Computed<T>): T { |
||||||
|
return (isSignal(signal) ? signal.value : signal) as T; |
||||||
|
} |
||||||
|
|
||||||
|
export const isFunction = (val: unknown): val is Function => |
||||||
|
typeof val === 'function' |
||||||
|
|
||||||
|
export function toValue<T>(source: MaybeSignalOrGetter<T>): T { |
||||||
|
return isFunction(source) ? source() : unSignal(source) |
||||||
|
} |
@ -1,3 +1,2 @@ |
|||||||
export * from "./computed"; |
export * from "./core"; |
||||||
export * from "./signal"; |
|
||||||
export * from "./deepSignal"; |
export * from "./deepSignal"; |
||||||
|
@ -1,26 +0,0 @@ |
|||||||
import { Signal as AlienSignal } from 'alien-signals'; |
|
||||||
export function signal<T>(): Signal<T | undefined>; |
|
||||||
export function signal<T>(oldValue: T): Signal<T>; |
|
||||||
export function signal<T>(oldValue?: T): Signal<T | undefined> { |
|
||||||
return new Signal(oldValue); |
|
||||||
} |
|
||||||
|
|
||||||
export class Signal<T = any> extends AlienSignal { |
|
||||||
constructor( |
|
||||||
currentValue: T |
|
||||||
) { |
|
||||||
super(currentValue); |
|
||||||
} |
|
||||||
|
|
||||||
get value(): T { |
|
||||||
return this.get() |
|
||||||
} |
|
||||||
|
|
||||||
set value(value: T) { |
|
||||||
this.set(value) |
|
||||||
} |
|
||||||
|
|
||||||
peek(): T { |
|
||||||
return this.currentValue; |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue