From 5d45cef1f0c6691431adb56133cb2dd97bffef89 Mon Sep 17 00:00:00 2001 From: Soybean Date: Thu, 25 Apr 2024 15:00:47 +0800 Subject: [PATCH] perf(hooks): perf useSignal --- packages/hooks/src/use-signal.ts | 73 ++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 17 deletions(-) diff --git a/packages/hooks/src/use-signal.ts b/packages/hooks/src/use-signal.ts index e07d786f7..fa9d62650 100644 --- a/packages/hooks/src/use-signal.ts +++ b/packages/hooks/src/use-signal.ts @@ -1,5 +1,12 @@ -import { computed, shallowRef, triggerRef } from 'vue'; -import type { ComputedGetter, DebuggerOptions, ShallowRef, WritableComputedOptions, WritableComputedRef } from 'vue'; +import { computed, ref, shallowRef, triggerRef } from 'vue'; +import type { + ComputedGetter, + DebuggerOptions, + Ref, + ShallowRef, + WritableComputedOptions, + WritableComputedRef +} from 'vue'; type Updater = (value: T) => T; type Mutator = (value: T) => void; @@ -7,26 +14,27 @@ type Mutator = (value: T) => void; /** * Signal is a reactive value that can be set, updated or mutated * - * ```ts - * const count = useSignal(0); + * @example + * ```ts + * const count = useSignal(0); * - * // `watchEffect` - * watchEffect(() => { + * // `watchEffect` + * watchEffect(() => { * console.log(count()); - * }); + * }); * - * // watch - * watch(count, value => { + * // watch + * watch(count, value => { * console.log(value); - * }); + * }); * - * // useComputed - * const double = useComputed(() => count() * 2); - * const writeableDouble = useComputed({ + * // useComputed + * const double = useComputed(() => count() * 2); + * const writeableDouble = useComputed({ * get: () => count() * 2, * set: value => count.set(value / 2) - * }); - * ``` + * }); + * ``` */ export interface Signal { (): Readonly; @@ -56,14 +64,43 @@ export interface Signal { * @param mutator */ mutate(mutator: Mutator): void; + /** + * Get the reference of the signal + * + * Sometimes it can be useful to make `v-model` work with the signal + * + * ```vue + * ; + * + * + * ``` + */ + getRef(): Readonly>>; } export interface ReadonlySignal { (): Readonly; } -export function useSignal(initialValue: T): Signal { - const state = shallowRef(initialValue); +export interface SignalOptions { + /** + * Whether to use `ref` to store the value + * + * @default false use `sharedRef` to store the value + */ + useRef?: boolean; +} + +export function useSignal(initialValue: T, options?: SignalOptions): Signal { + const { useRef } = options || {}; + + const state = useRef ? (ref(initialValue) as Ref) : shallowRef(initialValue); return createSignal(state); } @@ -101,5 +138,7 @@ function createSignal(state: ShallowRef | WritableComputedRef): Signal< triggerRef(state); }; + signal.getRef = () => state as Readonly>>; + return signal; }