diff --git a/src/index.ts b/src/index.ts index 2ecd3cc..125753b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,61 +1,59 @@ -import { Atom, Store, Action } from '@reatom/core' -import { onCleanup, createContext, useContext, createSignal, Accessor, Context } from "solid-js"; +import { Atom, AtomState, Store, Action, defaultStore, getState } from '@reatom/core' +import { onCleanup, createContext, useContext, createSignal, Accessor } from "solid-js"; -const defaultMapper = (atomValue: any) => atomValue +export const reatomContext = createContext(defaultStore); -export const context: Context = createContext(null); +function bindActionCreator( + store: Store, + actionCreator: (payload: T) => Action | Action[] | void, +) { + return (payload: T) => { + const action = actionCreator(payload); -export const { Provider } = context; + if (action) { + store.dispatch(action) + } + } +} -export function createAtomHook(ctx = context) { - const useAtom = (atom: Atom, selector: (atomValue: TI) => TO = defaultMapper): Accessor => { - const store = useContext(ctx); - - if (!store) throw new Error('[reatom] The provider is not defined'); - - const [state, setState] = createSignal(selector(store.getState(atom))); +export function useAction( + actionCreator: (payload: T) => Action | Action[] | void, +) { + const store = useContext(reatomContext); - const unsubscribe = store.subscribe(atom, (value) => { - setState(() => selector(value)) - }); + return bindActionCreator(store, actionCreator); +} - onCleanup(() => unsubscribe()); - - return state; - } - return useAtom; +type ActionCreators = { + [K in keyof T]: T[K] extends (...a: infer Args) => Action + ? (...args: Args) => void + : never } -export const useAtom = createAtomHook(); - -type AnyActionCreator = (...args: any[]) => Action | void - -export function createActionHook(ctx = context) { - function useAction( - cb: AC, - ): (...args: Parameters) => void - function useAction(cb: () => Action | void, deps?: any[]): () => void - function useAction( - cb: (a: T) => Action | void, - ): (payload: T) => void - function useAction( - cb: AnyActionCreator, - ): (...args: any[]) => void { - const store = useContext(ctx) - - if (!store) throw new Error('[reatom] The provider is not defined') - if (typeof cb !== 'function') { - throw new TypeError('[reatom] `useAction` argument must be a function') - } - return (...args) => { - const action = cb(...args) - if (action) store.dispatch(action) - }; - } +export function useAtom( + atom: T, +): [state: Accessor>, bindedActionCreators: ActionCreators] { + const store = useContext(reatomContext); + + const [state, setState] = createSignal(getState(atom, store)); + + const unsubscribe = store.subscribe(atom, (value) => { + setState(value) + }); - return useAction; + onCleanup(() => unsubscribe()); + + return [ + state, + Object.entries(atom).reduce((acc, [k, ac]) => { + // @ts-expect-error + if (isActionCreator(ac)) acc[k] = bindActionCreator(store, ac) + return acc + }, {} as ActionCreators) + ]; } -export const useAction = createActionHook(); + +