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 (
(dispatch(actions.updateSomeField, 'the new state'))}
+ onClick={() => (test.dispatch(actions.updateSomeField, 'wow-some-stuff'))}
>
- {test.someField}
+ {test.current.someField}
)
}
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 (
(dispatch(actions.updateSomeField, 'not anymore!'))}
+ onClick={() => (test.dispatch(actions.updateSomeField, 'not anymore!'))}
>
- {test.someField}
+ {test.current.someField}
)
}
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 (
(dispatch(actions.updateButtonText, 'the new state'))}
+ onClick={() => (dispatch(substates.test, actions.updateButtonText, 'the new state'))}
>
the button
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 = () => {
<>
(
- testDispatch(actions.test.updateButtonText, 'the new state')
+ test.dispatch(actions.test.updateButtonText, 'the new state')
)}
>
- {test.field1}
+ {test.current.field1}
(
- anotherTestDispatch(actions.anotherTest.updateOtherButtonText, 'baz')
+ dispatch(substates.anotherTest, actions.anotherTest.updateOtherButtonText, 'baz')
)}
>
Dispatch action to update "anotherTest"
diff --git a/packages/examples-18/src/components/ReplaceEntireStateExample.tsx b/packages/examples-18/src/components/ReplaceEntireStateExample.tsx
index 554393e..b47644c 100644
--- a/packages/examples-18/src/components/ReplaceEntireStateExample.tsx
+++ b/packages/examples-18/src/components/ReplaceEntireStateExample.tsx
@@ -19,13 +19,13 @@ const actions = {
}
const ReplaceEntireStateExample = () => {
- const [test, dispatch] = useSubstate(substates.test)
+ const test = useSubstate(substates.test)
return (
(dispatch(actions.updateButtonText, 'after'))}
+ onClick={() => (test.dispatch(actions.updateButtonText, 'after'))}
>
- {test}
+ {test.current}
)
}
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. */