mirror of https://github.com/sveltejs/svelte
chore: move reactivity code around (#10696)
* move some code * split computations.js into deriveds.js and effects.js * move reactivity types into separate .d.ts file * move some signal code --------- Co-authored-by: Rich Harris <rich.harris@vercel.com>pull/10697/head
parent
2d15c9de3f
commit
aa29a853dd
@ -0,0 +1,36 @@
|
||||
import { CLEAN, DERIVED, UNINITIALIZED, UNOWNED } from '../constants.js';
|
||||
import { current_block, current_consumer, current_effect } from '../runtime.js';
|
||||
import { create_computation_signal, push_reference } from './effects.js';
|
||||
import { default_equals, safe_equal } from './equality.js';
|
||||
|
||||
/**
|
||||
* @template V
|
||||
* @param {() => V} fn
|
||||
* @returns {import('../types.js').ComputationSignal<V>}
|
||||
*/
|
||||
/*#__NO_SIDE_EFFECTS__*/
|
||||
export function derived(fn) {
|
||||
const is_unowned = current_effect === null;
|
||||
const flags = is_unowned ? DERIVED | UNOWNED : DERIVED;
|
||||
const signal = /** @type {import('../types.js').ComputationSignal<V>} */ (
|
||||
create_computation_signal(flags | CLEAN, UNINITIALIZED, current_block)
|
||||
);
|
||||
signal.i = fn;
|
||||
signal.e = default_equals;
|
||||
if (current_consumer !== null) {
|
||||
push_reference(current_consumer, signal);
|
||||
}
|
||||
return signal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template V
|
||||
* @param {() => V} fn
|
||||
* @returns {import('../types.js').ComputationSignal<V>}
|
||||
*/
|
||||
/*#__NO_SIDE_EFFECTS__*/
|
||||
export function derived_safe_equal(fn) {
|
||||
const signal = derived(fn);
|
||||
signal.e = safe_equal;
|
||||
return signal;
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @param {((value?: number) => number)} fn
|
||||
* @param {1 | -1} [d]
|
||||
* @returns {number}
|
||||
*/
|
||||
export function update_prop(fn, d = 1) {
|
||||
const value = fn();
|
||||
fn(value + d);
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {((value?: number) => number)} fn
|
||||
* @param {1 | -1} [d]
|
||||
* @returns {number}
|
||||
*/
|
||||
export function update_pre_prop(fn, d = 1) {
|
||||
const value = fn() + d;
|
||||
fn(value);
|
||||
return value;
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
import type { Block, ComponentContext, EqualsFunctions } from '#client';
|
||||
import type { DERIVED, EFFECT, PRE_EFFECT, RENDER_EFFECT, SOURCE } from '../constants';
|
||||
|
||||
export type SignalFlags =
|
||||
| typeof SOURCE
|
||||
| typeof DERIVED
|
||||
| typeof EFFECT
|
||||
| typeof PRE_EFFECT
|
||||
| typeof RENDER_EFFECT;
|
||||
export type EffectType = typeof EFFECT | typeof PRE_EFFECT | typeof RENDER_EFFECT;
|
||||
|
||||
// We keep two shapes rather than a single monomorphic shape to improve the memory usage.
|
||||
// Source signals don't need the same shape as they simply don't do as much as computations
|
||||
// (effects and derived signals). Thus we can improve the memory profile at the slight cost
|
||||
// of some runtime performance.
|
||||
|
||||
export type SourceSignal<V = unknown> = {
|
||||
/** consumers: Signals that read from the current signal */
|
||||
c: null | ComputationSignal[];
|
||||
/** equals: For value equality */
|
||||
e: null | EqualsFunctions;
|
||||
/** flags: The types that the signal represent, as a bitwise value */
|
||||
f: SignalFlags;
|
||||
/** value: The latest value for this signal */
|
||||
v: V;
|
||||
// write version
|
||||
w: number;
|
||||
};
|
||||
|
||||
export type SourceSignalDebug = {
|
||||
/** This is DEV only */
|
||||
inspect: Set<Function>;
|
||||
};
|
||||
|
||||
export type ComputationSignal<V = unknown> = {
|
||||
/** block: The block associated with this effect/computed */
|
||||
b: null | Block;
|
||||
/** consumers: Signals that read from the current signal */
|
||||
c: null | ComputationSignal[];
|
||||
/** context: The associated component if this signal is an effect/computed */
|
||||
x: null | ComponentContext;
|
||||
/** dependencies: Signals that this signal reads from */
|
||||
d: null | Signal<V>[];
|
||||
/** destroy: Thing(s) that need destroying */
|
||||
y: null | (() => void) | Array<() => void>;
|
||||
/** equals: For value equality */
|
||||
e: null | EqualsFunctions;
|
||||
/** The types that the signal represent, as a bitwise value */
|
||||
f: SignalFlags;
|
||||
/** init: The function that we invoke for effects and computeds */
|
||||
i:
|
||||
| null
|
||||
| (() => V)
|
||||
| (() => void | (() => void))
|
||||
| ((b: Block, s: Signal) => void | (() => void));
|
||||
/** references: Anything that a signal owns */
|
||||
r: null | ComputationSignal[];
|
||||
/** value: The latest value for this signal, doubles as the teardown for effects */
|
||||
v: V;
|
||||
/** level: the depth from the root signal, used for ordering render/pre-effects topologically **/
|
||||
l: number;
|
||||
/** write version: used for unowned signals to track if their depdendencies are dirty or not **/
|
||||
w: number;
|
||||
};
|
||||
|
||||
export type Signal<V = unknown> = SourceSignal<V> | ComputationSignal<V>;
|
||||
|
||||
export type SignalDebug<V = unknown> = SourceSignalDebug & Signal<V>;
|
||||
|
||||
export type EffectSignal = ComputationSignal<null | (() => void)>;
|
||||
|
||||
export type MaybeSignal<T = unknown> = T | Signal<T>;
|
||||
|
||||
export type UnwrappedSignal<T> = T extends Signal<infer U> ? U : T;
|
Loading…
Reference in new issue