1
0
mirror of https://github.com/robonen/tools.git synced 2026-03-20 19:04:46 +00:00

refactor: change separate tools by category

This commit is contained in:
2025-05-19 17:43:42 +07:00
parent d55737df2f
commit 78fb4da82a
158 changed files with 32 additions and 24 deletions

View File

@@ -0,0 +1,40 @@
import { describe, it, vi, expect } from 'vitest';
import { ref, reactive } from 'vue';
import { useAppSharedState } from '.';
describe('useAppSharedState', () => {
it('initialize state only once', () => {
const stateFactory = (initValue?: number) => {
const count = ref(initValue ?? 0);
return { count };
};
const useSharedState = useAppSharedState(stateFactory);
const state1 = useSharedState(1);
const state2 = useSharedState(2);
expect(state1.count.value).toBe(1);
expect(state2.count.value).toBe(1);
expect(state1).toBe(state2);
});
it('return the same state object across different calls', () => {
const stateFactory = () => {
const state = reactive({ count: 0 });
const increment = () => state.count++;
return { state, increment };
};
const useSharedState = useAppSharedState(stateFactory);
const sharedState1 = useSharedState();
const sharedState2 = useSharedState();
expect(sharedState1.state.count).toBe(0);
sharedState1.increment();
expect(sharedState1.state.count).toBe(1);
expect(sharedState2.state.count).toBe(1);
expect(sharedState1).toBe(sharedState2);
});
});

View File

@@ -0,0 +1,42 @@
import type { AnyFunction } from '@robonen/stdlib';
import { effectScope } from 'vue';
// TODO: maybe we should control subscriptions and dispose them when the child scope is disposed
/**
* @name useAppSharedState
* @category State
* @description Provides a shared state object for use across Vue instances
*
* @param {Function} stateFactory A factory function that returns the shared state object
* @returns {Function} A function that returns the shared state object
*
* @example
* const useSharedState = useAppSharedState((initValue?: number) => {
* const count = ref(initValue ?? 0);
* return { count };
* });
*
* @example
* const useSharedState = useAppSharedState(() => {
* const state = reactive({ count: 0 });
* const increment = () => state.count++;
* return { state, increment };
* });
*
* @since 0.0.1
*/
export function useAppSharedState<Fn extends AnyFunction>(stateFactory: Fn) {
let initialized = false;
let state: ReturnType<Fn>;
const scope = effectScope(true);
return ((...args: Parameters<Fn>) => {
if (!initialized) {
state = scope.run(() => stateFactory(...args));
initialized = true;
}
return state;
});
}