Skip to content

Commit

Permalink
fix: lazily load state from generators
Browse files Browse the repository at this point in the history
  • Loading branch information
Harvtronix committed Sep 18, 2024
1 parent 16699b3 commit 1e69f7f
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 4 deletions.
5 changes: 5 additions & 0 deletions packages/examples-18/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import BasicExample from './components/BasicExample.js'
import PatchEffectExample from './components/PatchEffectExample.js'
import ReplaceEntireStateExample from './components/ReplaceEntireStateExample.js'
import DispatchOnlyExample from './components/DispatchOnlyExample.js'
import BasicExampleWithGenerator from './components/BasicExampleWithGenerator.js'

const App = () => {
return (
Expand All @@ -10,6 +11,10 @@ const App = () => {
<h1>Basic Example</h1>
<BasicExample />
</div>
<div>
<h1>Basic Example with Generator</h1>
<BasicExampleWithGenerator />
</div>
<div>
<h1>Patch Effect Example</h1>
<PatchEffectExample />
Expand Down
38 changes: 38 additions & 0 deletions packages/examples-18/src/components/BasicExampleWithGenerator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
createSubstate,
createAction,
useSubstate,
} from 'react-substate'

interface Test {
someField: string
}

// Set up a substate
const substates = {
test: createSubstate<Test>(() => ({someField: 'it is generated!'})),
}

// Set up some dispatchable actions
const actions = {
updateSomeField: createAction(
(draft: Test, payload: Test['someField']) => {
draft.someField = payload // Will become "not anymore"
}
)
}

// Use it like you would `useReducer` or `useState`
const BasicExampleWithGenerator = () => {
const [test, dispatch] = useSubstate(substates.test)

return (
<button
onClick={() => (dispatch(actions.updateSomeField, 'not anymore!'))}
>
{test.someField}
</button>
)
}

export default BasicExampleWithGenerator
2 changes: 1 addition & 1 deletion packages/react-substate/.npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ src/
.github/

package-lock.json
tsconfig.json
tsconfig.cjs.json
rollup.config.js

!dist/
3 changes: 3 additions & 0 deletions packages/react-substate/src/managers/DevToolsManager.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {log} from '../Debug.js'
import {
Actions,
DevTools,
Expand Down Expand Up @@ -25,6 +26,7 @@ function setDevToolsEnabled (isEnabled: boolean) {
const w = typeof window !== 'undefined' ? (window as any) : null

const interval = setInterval(() => {
log('Attempting to connect to redux devtools...')
devTools = w?.__REDUX_DEVTOOLS_EXTENSION__?.connect()

if (!devTools) {
Expand All @@ -33,6 +35,7 @@ function setDevToolsEnabled (isEnabled: boolean) {

clearInterval(interval)

log('Connected to redux devtools!')
devTools.init(transformState(substates))
}, 3000)
}
Expand Down
15 changes: 12 additions & 3 deletions packages/react-substate/src/managers/SubstateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function createSubstate <Type extends Substates[any]['state']> (
substates[substateKey] = {
listeners: [],
patchEffects: [],
state: initialData instanceof Function ? initialData() : initialData
state: initialData
}

// Notify the DevTools
Expand All @@ -39,7 +39,8 @@ function createSubstate <Type extends Substates[any]['state']> (

/**
* Returns a substate with the provided key, or throws an exception if the key does not point to a
* valid substate.
* valid substate. Converts the substate from a generator function to its generated value the first
* time it is called for a given substate.
*
* @param {SubstateKey<*>} substateKey The key of the substate to retrieve.
* @returns {*} The substate.
Expand All @@ -48,8 +49,16 @@ function getSubstate <Type> (substateKey: SubstateKey<Type>): Type {
if (!hasSubstate(substateKey)) {
throw new Error(`Substate key ${substateKey} not registered`)
}

const substate = substates[substateKey.id]

if (substate?.state instanceof Function) {
console.log('converting state generator to state object')
substate.state = substate.state()
}

// Null check performed in previous guard clause
return substates[substateKey.id]!.state as Type
return substate?.state as Type
}

/**
Expand Down

0 comments on commit 1e69f7f

Please sign in to comment.