import type { RafFrame } from '../../_util/raf';
import raf from '../../_util/raf';
import type { Ref, UnwrapRef } from 'vue';
import { onBeforeUnmount, ref, shallowRef } from 'vue';
export type Updater<State> = (prev: State) => State;
export function useLayoutState<State>(
defaultState: State,
): [Ref<State>, (updater: Updater<State>) => void] {
const stateRef = shallowRef<State>(defaultState);
let rafId: RafFrame;
const updateBatchRef = shallowRef<Updater<State>[]>([]);
function setFrameState(updater: Updater<State>) {
updateBatchRef.value.push(updater);
raf.cancel(rafId);
rafId = raf(() => {
const prevBatch = updateBatchRef.value;
// const prevState = stateRef.value;
updateBatchRef.value = [];
prevBatch.forEach(batchUpdater => {
stateRef.value = batchUpdater(stateRef.value as State);
});
}
onBeforeUnmount(() => {
return [stateRef as Ref<State>, setFrameState];
/** Lock frame, when frame pass reset the lock. */
export function useTimeoutLock<State>(
defaultState?: State,
): [(state: UnwrapRef<State>) => void, () => UnwrapRef<State> | null] {
const frameRef = ref<State | null>(defaultState || null);
const timeoutRef = ref<any>();
function cleanUp() {
clearTimeout(timeoutRef.value);
function setState(newState: UnwrapRef<State>) {
frameRef.value = newState;
cleanUp();
timeoutRef.value = setTimeout(() => {
frameRef.value = null;
timeoutRef.value = undefined;
}, 100);
function getState() {
return frameRef.value;
return [setState, getState];