diff --git a/.eslintrc.json b/.eslintrc.json index e0d632a..389a4c1 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,6 +35,8 @@ } } ], + "jsdoc/require-param-type": "off", + "jsdoc/require-returns-type": "off", "max-len": ["warn", 100], "no-undef": "off", "no-unused-vars": "off", diff --git a/packages/examples-18/src/components/BasicExample.tsx b/packages/examples-18/src/components/BasicExample.tsx index b6f37ab..60f2263 100644 --- a/packages/examples-18/src/components/BasicExample.tsx +++ b/packages/examples-18/src/components/BasicExample.tsx @@ -26,15 +26,15 @@ const actions = { ) } -// Use it like you would `useReducer` or `useState` +// Use it (mostly) like you would `useReducer` or `useState` const BasicExample = () => { - const [test, dispatch] = useSubstate(substates.test) + const test = useSubstate(substates.test) return ( ) } diff --git a/packages/examples-18/src/components/BasicExampleWithGenerator.tsx b/packages/examples-18/src/components/BasicExampleWithGenerator.tsx index a257ae1..c6e949a 100644 --- a/packages/examples-18/src/components/BasicExampleWithGenerator.tsx +++ b/packages/examples-18/src/components/BasicExampleWithGenerator.tsx @@ -8,7 +8,7 @@ interface Test { someField: string } -// Set up a substate +// Set up a substate by passing a state generator function to seed the Substate const substates = { test: createSubstate(() => ({someField: 'it is generated!'})), } @@ -22,15 +22,15 @@ const actions = { ) } -// Use it like you would `useReducer` or `useState` +// Use the hook to get the current state data and dispatch actions const BasicExampleWithGenerator = () => { - const [test, dispatch] = useSubstate(substates.test) + const test = useSubstate(substates.test) return ( ) } diff --git a/packages/examples-18/src/components/DispatchOnlyExample.tsx b/packages/examples-18/src/components/DispatchOnlyExample.tsx index 91e2513..521e8a8 100644 --- a/packages/examples-18/src/components/DispatchOnlyExample.tsx +++ b/packages/examples-18/src/components/DispatchOnlyExample.tsx @@ -24,9 +24,9 @@ const actions = { ) } -// Use it like you would `useReducer` or `useState` +// Use it similarly to how you would `useReducer` or `useState` const DispatchOnlyExample = () => { - const dispatch = useDispatch(substates.test) + const dispatch = useDispatch() useEffect(() => { console.log('I will only render this one time!') // This will only ever be called one time @@ -34,7 +34,7 @@ const DispatchOnlyExample = () => { return ( diff --git a/packages/examples-18/src/components/PatchEffectExample.tsx b/packages/examples-18/src/components/PatchEffectExample.tsx index b5d7f3b..9d41b67 100644 --- a/packages/examples-18/src/components/PatchEffectExample.tsx +++ b/packages/examples-18/src/components/PatchEffectExample.tsx @@ -36,8 +36,8 @@ const actions = { } const PatchEffectExample = () => { - const [test, testDispatch] = useSubstate(substates.test) - const anotherTestDispatch = useDispatch(substates.anotherTest) + const test = useSubstate(substates.test) + const dispatch = useDispatch() // Create a patch effect for a single substate usePatchEffect((patches) => { @@ -55,15 +55,15 @@ const PatchEffectExample = () => { <> ) } diff --git a/packages/react-substate/src/Interfaces.ts b/packages/react-substate/src/Interfaces.ts index 2765530..32f4b18 100644 --- a/packages/react-substate/src/Interfaces.ts +++ b/packages/react-substate/src/Interfaces.ts @@ -1,6 +1,5 @@ -interface ActionStateModifier { - (draft: Draft, payload: Payload): Draft | void -} +type ActionStateModifier = + (draft: Draft, payload: Payload) => Draft | void interface Actions { [key: string]: ActionStateModifier @@ -11,9 +10,7 @@ interface ActionKey { __payload: () => Payload } -interface PatchEffectFunction { - (patches: Array): void -} +type PatchEffectFunction = (patches: Array) => void interface Substates { [key: string]: { @@ -28,20 +25,18 @@ interface SubstateKey { __type: () => Type } -interface Dispatcher { - ( - actionKey: ActionKey, - payload: ReturnType - ): void -} +type Dispatcher = + >( + actionKey: Key, + payload: ReturnType + ) => void -interface GlobalDispatcher{ - ( - substateKey: SubstateKey, - actionKey: ActionKey, - payload: ReturnType - ): void -} +type GenericDispatcher = + , AKey extends ActionKey>( + substateKey: SKey, + actionKey: AKey, + payload: ReturnType + ) => void interface DevToolsState { [key: string]: { @@ -71,7 +66,7 @@ export type { DevToolsOperation, DevToolsState, Dispatcher, - GlobalDispatcher, + GenericDispatcher, PatchEffectFunction, Substates, SubstateKey diff --git a/packages/react-substate/src/hooks/useDispatch.ts b/packages/react-substate/src/hooks/useDispatch.ts index 61df4e2..e4fd4fa 100644 --- a/packages/react-substate/src/hooks/useDispatch.ts +++ b/packages/react-substate/src/hooks/useDispatch.ts @@ -1,23 +1,28 @@ import {useCallback} from 'react' import {dispatch} from '../dispatch.js' -import {ActionKey, Dispatcher, SubstateKey} from '../Interfaces.js' +import {ActionKey, GenericDispatcher, SubstateKey} from '../Interfaces.js' /** * Hook that allows a component to receive a reference to a dispatch function that can be called to - * update a particular substate without also listening for changes to any substates. + * update ANY substate without also listening for changes to a substate. * - * @param {SubstateKey<*>} substateKey The substate to be modified by actions dispatched via the - * returned dispatch function. - * @returns {Dispatcher} Dispatch function that can be called to update the substate. + * Similar to the dispatch function obtained via `useSubstate`, except this function requires a + * reference to a Substate as the first argument. + * + * @returns Dispatch function that can be called to update any substate. */ -export function useDispatch (substateKey: SubstateKey): Dispatcher { +export function useDispatch (): GenericDispatcher { // Since we are creating a function in this hook, memoize it so it remains the same across // re-renders return useCallback( - (actionKey: ActionKey, payload: Payload) => ( + ( + substateKey: SubstateKey, + actionKey: ActionKey, + payload: Payload + ) => ( dispatch(substateKey, actionKey, payload) ), - [substateKey] + [] ) } diff --git a/packages/react-substate/src/hooks/useGlobalDispatch.ts b/packages/react-substate/src/hooks/useGlobalDispatch.ts deleted file mode 100644 index dbb15d3..0000000 --- a/packages/react-substate/src/hooks/useGlobalDispatch.ts +++ /dev/null @@ -1,25 +0,0 @@ -import {useCallback} from 'react' - -import {dispatch} from '../dispatch.js' -import {ActionKey, GlobalDispatcher, SubstateKey} from '../Interfaces.js' - -/** - * Hook that allows a component to receive a reference to a dispatch function that can be called to - * update substates without also listening for changes to any substates. - * - * @returns {GlobalDispatcher} Dispatch function that can be called to update the substate. - */ -export function useGlobalDispatch (): GlobalDispatcher { - // Since we are creating a function in this hook, memoize it so it remains the same across - // re-renders - return useCallback( - ( - substateKey: SubstateKey, - actionKey: ActionKey, - payload: Payload - ) => ( - dispatch(substateKey, actionKey, payload) - ), - [] - ) -} diff --git a/packages/react-substate/src/hooks/useSubstate.ts b/packages/react-substate/src/hooks/useSubstate.ts index 0be58e7..c35cdf8 100644 --- a/packages/react-substate/src/hooks/useSubstate.ts +++ b/packages/react-substate/src/hooks/useSubstate.ts @@ -1,30 +1,39 @@ -import {useEffect, useState} from 'react' +import {useCallback, useEffect, useState} from 'react' import {log} from '../Debug.js' -import {Dispatcher, SubstateKey} from '../Interfaces.js' +import {dispatch} from '../dispatch.js' +import {ActionKey, Dispatcher, SubstateKey} from '../Interfaces.js' import { getSubstate, hasSubstate, registerListener, unregisterListener } from '../managers/SubstateManager.js' -import {useDispatch} from './useDispatch.js' /** * Hook that allows a component to listen for changes to a substate and receive a reference to a * dispatch function that can be called to update that substate. * - * @param {SubstateKey<*>} substateKey The key of the substate to return. The returned dispatch + * @param substateKey The key of the substate to return. The returned dispatch * function will be scoped to this substate as well. - * @returns {Array} Array whose `0` index is the current value of the substate and whose `1` index - * is a dispatch function that can be called to update the substate. + * @returns Object containing the current value of the Substate and a dispatch function that can be + * called to update it. */ -export function useSubstate (substateKey: SubstateKey): [Type, Dispatcher] { +export function useSubstate ( + substateKey: SubstateKey +): {current: Type, dispatch: Dispatcher} { if (!hasSubstate(substateKey)) { throw new Error('No substate found with key ' + substateKey) } - const dispatch = useDispatch(substateKey) + // Since we are creating a function in this hook, memoize it so it remains the same across + // re-renders + const substateDispatch: Dispatcher = useCallback( + (actionKey: ActionKey, payload: Payload) => ( + dispatch(substateKey, actionKey, payload) + ), + [substateKey] + ) const [, setState] = useState() @@ -38,8 +47,8 @@ export function useSubstate (substateKey: SubstateKey): [Type, Disp } }, [substateKey, setState]) - return [ - getSubstate(substateKey), - dispatch - ] + return { + current: getSubstate(substateKey), + dispatch: substateDispatch + } } diff --git a/packages/react-substate/src/index.ts b/packages/react-substate/src/index.ts index db90f03..776044a 100644 --- a/packages/react-substate/src/index.ts +++ b/packages/react-substate/src/index.ts @@ -1,9 +1,8 @@ import {setDebugEnabled} from './Debug.js' import {useDispatch} from './hooks/useDispatch.js' -import {useGlobalDispatch} from './hooks/useGlobalDispatch.js' import {usePatchEffect} from './hooks/usePatchEffect.js' import {useSubstate} from './hooks/useSubstate.js' -import {Dispatcher, GlobalDispatcher} from './Interfaces.js' +import {Dispatcher, GenericDispatcher} from './Interfaces.js' import {createAction} from './managers/ActionManager.js' import {setDevToolsEnabled} from './managers/DevToolsManager.js' import {createSubstate} from './managers/SubstateManager.js' @@ -26,12 +25,11 @@ export { setDevToolsEnabled, useDispatch, - useGlobalDispatch, usePatchEffect, useSubstate } export type { Dispatcher, - GlobalDispatcher + GenericDispatcher } diff --git a/packages/react-substate/tsconfig.json b/packages/react-substate/tsconfig.json index 5e52456..04a0bfb 100644 --- a/packages/react-substate/tsconfig.json +++ b/packages/react-substate/tsconfig.json @@ -50,7 +50,7 @@ // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ "outDir": "./dist/mjs", /* Specify an output folder for all emitted files. */ - "removeComments": true, /* Disable emitting comments. */ + "removeComments": false, /* Disable emitting comments. */ // "noEmit": true, /* Disable emitting files from a compilation. */ // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */