Skip to content

Commit

Permalink
feat(ui/store): FavolinkStore class, createFavolinkStore, 관련 hook 추가 (#…
Browse files Browse the repository at this point in the history
…315)

* feat(ui/store): FavolinkStore class, createFavolinkStore 추가

* feat(ui/store): store 관련 hook 추가
  • Loading branch information
sukvvon authored Aug 16, 2024
1 parent c486c5f commit b748844
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 0 deletions.
26 changes: 26 additions & 0 deletions packages/ui/src/store/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useSyncExternalStore } from 'react';
import { type FavolinkStoreObserver } from './store';

export function useFavolinkStore<T>(store: FavolinkStoreObserver<T>) {
const state = useSyncExternalStore(
store.subscribe,
store.getState,
store.getState,
);

return [state, store.setState] as const;
}

export function useFavolinkStoreValue<T>(store: FavolinkStoreObserver<T>) {
const state = useSyncExternalStore(
store.subscribe,
store.getState,
store.getState,
);

return state;
}

export function useSetFavolinkStore<T>(store: FavolinkStoreObserver<T>) {
return store.setState;
}
11 changes: 11 additions & 0 deletions packages/ui/src/store/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* eslint-disable @stylistic/padding-line-between-statements */
export {
FavolinkStore,
type FavolinkStoreObserver,
createFavolinkStore,
} from './store';
export {
useFavolinkStore,
useFavolinkStoreValue,
useSetFavolinkStore,
} from './hooks';
53 changes: 53 additions & 0 deletions packages/ui/src/store/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export interface FavolinkStoreObserver<T> {
getState: () => T;
setState: (next: SetStateAction<T>) => void;
subscribe: (listener: () => void) => () => void;
emitChange: () => void;
}

type SetStateFn<T> = (prevState: T) => T;

type SetStateAction<T> = SetStateFn<T> | T;

export class FavolinkStore<T> implements FavolinkStoreObserver<T> {
private state: T;
private listeners: (() => void)[] = [];

constructor(initialState: T) {
this.state = initialState;
}

getState = () => {
return this.state;
};

setState = (next: SetStateAction<T>) => {
const setter = next as SetStateFn<T>;
const nextValue = typeof next === 'function' ? setter(this.state) : next;

if (this.state === nextValue) {
return;
}

this.state = nextValue;
this.emitChange();
};

subscribe = (listener: () => void) => {
this.listeners = [...this.listeners, listener];

return () => {
this.listeners = this.listeners.filter((l) => l !== listener);
};
};

emitChange = () => {
this.listeners.forEach((listener) => {
listener();
});
};
}

export function createFavolinkStore<T>(initialState: T) {
return new FavolinkStore(initialState);
}

0 comments on commit b748844

Please sign in to comment.