memos/web/src/labs/createStore.ts

64 lines
1.4 KiB
TypeScript

export type State = Readonly<Record<string, any>>;
export type Action = {
type: string;
payload: any;
};
export type Reducer<S extends State, A extends Action> = (s: S, a: A) => S;
type Listener<S extends State> = (ns: S, ps?: S) => void;
type Unsubscribe = () => void;
export interface Store<S extends State, A extends Action> {
dispatch: (a: A) => void;
getState: () => S;
subscribe: (listener: Listener<S>) => Unsubscribe;
}
/**
* Toy-Redux
* @param preloadedState initial state
* @param reducer reducer pure function
* @returns store
*/
function createStore<S extends State, A extends Action>(preloadedState: S, reducer: Reducer<S, A>): Store<Readonly<S>, A> {
const listeners: Listener<S>[] = [];
let currentState = preloadedState;
const dispatch = (action: A) => {
const nextState = reducer(currentState, action);
const prevState = currentState;
currentState = nextState;
for (const cb of listeners) {
cb(currentState, prevState);
}
};
const subscribe = (listener: Listener<S>) => {
let isSubscribed = true;
listeners.push(listener);
return () => {
if (!isSubscribed) {
return;
}
const index = listeners.indexOf(listener);
listeners.splice(index, 1);
isSubscribed = false;
};
};
const getState = () => {
return currentState;
};
return {
dispatch,
getState,
subscribe,
};
}
export default createStore;