Skip to content

Commit

Permalink
perf(hooks): perf useSignal
Browse files Browse the repository at this point in the history
  • Loading branch information
honghuangdc committed Apr 25, 2024
1 parent d460e5c commit 5d45cef
Showing 1 changed file with 56 additions and 17 deletions.
73 changes: 56 additions & 17 deletions packages/hooks/src/use-signal.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,40 @@
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<T> = (value: T) => T;
type Mutator<T> = (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<T> {
(): Readonly<T>;
Expand Down Expand Up @@ -56,14 +64,43 @@ export interface Signal<T> {
* @param mutator
*/
mutate(mutator: Mutator<T>): void;
/**
* Get the reference of the signal
*
* Sometimes it can be useful to make `v-model` work with the signal
*
* ```vue
* <template>
* <input v-model="model.count" />
* </template>;
*
* <script setup lang="ts">
* const state = useSignal({ count: 0 }, { useRef: true });
*
* const model = state.getRef();
* </script>
* ```
*/
getRef(): Readonly<ShallowRef<Readonly<T>>>;
}

export interface ReadonlySignal<T> {
(): Readonly<T>;
}

export function useSignal<T>(initialValue: T): Signal<T> {
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<T>(initialValue: T, options?: SignalOptions): Signal<T> {
const { useRef } = options || {};

const state = useRef ? (ref(initialValue) as Ref<T>) : shallowRef(initialValue);

return createSignal(state);
}
Expand Down Expand Up @@ -101,5 +138,7 @@ function createSignal<T>(state: ShallowRef<T> | WritableComputedRef<T>): Signal<
triggerRef(state);
};

signal.getRef = () => state as Readonly<ShallowRef<Readonly<T>>>;

return signal;
}

0 comments on commit 5d45cef

Please sign in to comment.