From 09f64646781111e154ffdb2a753d8c7367a1381a Mon Sep 17 00:00:00 2001 From: Soybean Date: Thu, 25 Apr 2024 01:39:59 +0800 Subject: [PATCH] feat(hooks): add state hooks: useRef, useState, useSignal --- packages/hooks/src/index.ts | 1 + packages/hooks/src/use-state.ts | 81 +++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) create mode 100644 packages/hooks/src/use-state.ts diff --git a/packages/hooks/src/index.ts b/packages/hooks/src/index.ts index a36c84362..7ec0a971d 100644 --- a/packages/hooks/src/index.ts +++ b/packages/hooks/src/index.ts @@ -7,4 +7,5 @@ import useHookTable from './use-table'; export { useBoolean, useLoading, useCountDown, useContext, useSvgIconRender, useHookTable }; +export * from './use-state'; export * from './use-table'; diff --git a/packages/hooks/src/use-state.ts b/packages/hooks/src/use-state.ts new file mode 100644 index 000000000..41f1b3332 --- /dev/null +++ b/packages/hooks/src/use-state.ts @@ -0,0 +1,81 @@ +import { ref } from 'vue'; +import type { Ref } from 'vue'; + +/** + * useRef + * + * it is a simple ref management hook wrapped by vue3's ref function. + * + * to resolve the ref type problem about `UnwrapRef` + * + * @param initValue + */ +export function useRef(initValue: T) { + const refValue = ref(initValue) as Ref; + + return refValue; +} + +/** + * useState + * + * define a state and a setState function + * + * @param initValue + */ +export function useState(initValue: T) { + const state = useRef(initValue); + + function setState(value: T) { + state.value = value; + } + + return [state, setState] as const; +} + +interface Signal { + (): T; + /** + * the ref object of the signal, but it is readonly + * + * equal to `const ref = ref(initValue);` + */ + readonly ref: Readonly>; + /** + * set the value of the signal + * + * @param value + */ + set(value: T): void; + /** + * update the value of the signal + * + * @param fn update function + */ + update(fn: (value: T) => T): void; +} + +/** + * useSignal + * + * @param initValue + */ +export function useSignal(initValue: T) { + const [state, setState] = useState(initValue); + + function updateState(fn: (value: T) => T) { + const updatedValue = fn(state.value); + setState(updatedValue); + } + + const signal = function signal() { + return state.value; + } as Signal; + + (signal as any).ref = state; + + signal.set = setState; + signal.update = updateState; + + return signal; +}