mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
refactor(store): simplify state management + computeds (#321)
This commit is contained in:
@@ -1,32 +1,24 @@
|
||||
import type { Reactive } from '../../core/state';
|
||||
import type { State } from '../../core/state';
|
||||
|
||||
import { useState, useSyncExternalStore } from 'react';
|
||||
import { track } from '../../core/state';
|
||||
import { useSyncExternalStore } from 'react';
|
||||
|
||||
/**
|
||||
* Subscribe to reactive state and re-render when accessed properties change.
|
||||
*
|
||||
* Automatically tracks which properties are accessed during render and only
|
||||
* re-renders when those specific properties change.
|
||||
*
|
||||
* @param state - Reactive state created by `reactive()`
|
||||
* @returns The state, which triggers re-renders when accessed properties change
|
||||
* Subscribe to state and re-render when state changes.
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* function VolumeDisplay() {
|
||||
* const state = useSnapshot(store.state);
|
||||
* return <span>{Math.round(state.volume * 100)}%</span>;
|
||||
* const { volume } = useSnapshot(store.state);
|
||||
* return <span>{Math.round(volume * 100)}%</span>;
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useSnapshot<T extends object>(state: Reactive<T>): T {
|
||||
const [{ tracked, subscribe, getSnapshot, next }] = useState(() => track(state));
|
||||
|
||||
useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
||||
next();
|
||||
|
||||
return tracked;
|
||||
export function useSnapshot<T extends object>(state: State<T>): T {
|
||||
return useSyncExternalStore(
|
||||
onStoreChange => state.subscribe(onStoreChange),
|
||||
() => state.current,
|
||||
() => state.current,
|
||||
);
|
||||
}
|
||||
|
||||
export namespace useSnapshot {
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import type { TasksRecord } from '../../core/queue';
|
||||
import type { AnyStore, InferStoreTasks } from '../../core/store';
|
||||
|
||||
import { useCallback, useRef, useSyncExternalStore } from 'react';
|
||||
|
||||
import { subscribe } from '../../core/state';
|
||||
import { useSnapshot } from './use-snapshot';
|
||||
|
||||
/**
|
||||
* Subscribe to task queue state.
|
||||
@@ -11,9 +9,6 @@ import { subscribe } from '../../core/state';
|
||||
* Returns a record of all tasks keyed by request name.
|
||||
* Re-renders when any task is added, updated, or removed.
|
||||
*
|
||||
* @param store - The store instance to subscribe to
|
||||
* @returns Record of tasks keyed by request name
|
||||
*
|
||||
* @example
|
||||
* ```tsx
|
||||
* function TaskList() {
|
||||
@@ -31,22 +26,6 @@ import { subscribe } from '../../core/state';
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export function useTasks<S extends AnyStore>(store: S): TasksRecord<InferStoreTasks<S>> {
|
||||
const versionRef = useRef(0);
|
||||
|
||||
const subscribeToQueue = useCallback(
|
||||
(onStoreChange: () => void) =>
|
||||
subscribe(store.queue.tasks, () => {
|
||||
versionRef.current++;
|
||||
onStoreChange();
|
||||
}),
|
||||
[store],
|
||||
);
|
||||
|
||||
const getSnapshot = useCallback(() => versionRef.current, []);
|
||||
|
||||
useSyncExternalStore(subscribeToQueue, getSnapshot, getSnapshot);
|
||||
|
||||
// Return the tasks proxy directly
|
||||
return store.queue.tasks as TasksRecord<InferStoreTasks<S>>;
|
||||
export function useTasks<Store extends AnyStore>(store: Store): TasksRecord<InferStoreTasks<Store>> {
|
||||
return useSnapshot(store.queue.tasks) as TasksRecord<InferStoreTasks<Store>>;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('createStore', () => {
|
||||
const store = create();
|
||||
|
||||
expect(store).toBeDefined();
|
||||
expect(store.state).toEqual({ volume: 1, muted: false });
|
||||
expect(store.state.current).toEqual({ volume: 1, muted: false });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -55,7 +55,7 @@ describe('createStore', () => {
|
||||
});
|
||||
|
||||
expect(result.current).toBeDefined();
|
||||
expect(result.current.state).toEqual({ volume: 1, muted: false });
|
||||
expect(result.current.state.current).toEqual({ volume: 1, muted: false });
|
||||
});
|
||||
|
||||
it('destroys store on unmount', () => {
|
||||
|
||||
Reference in New Issue
Block a user