Skip to content

Commit 098b8a9

Browse files
feat(overmind-react): scoped tracking
1 parent 4e9b48b commit 098b8a9

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

packages/node_modules/overmind-react/src/__snapshots__/index.test.tsx.snap

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ exports[`React should allow using hooks 1`] = `
66
</h1>
77
`;
88

9+
exports[`React should allow using hooks with scoped tracking 1`] = `
10+
<h1>
11+
bar
12+
</h1>
13+
`;
14+
915
exports[`React should allow using mocked Overmind 1`] = `
1016
<h1>
1117
bar

packages/node_modules/overmind-react/src/index.test.tsx

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,68 @@ describe('React', () => {
5555
expect(renderCount).toBe(2)
5656
expect(tree).toMatchSnapshot()
5757
})
58+
test('should allow using hooks with scoped tracking', () => {
59+
let renderCount = 0
60+
61+
const doThis = ({ state }: Context) => {
62+
state.foo.push({ foo: 'bar2' })
63+
}
64+
const doThat = ({ state }: Context) => {
65+
state.foo[0].foo = 'bar3'
66+
}
67+
const state = {
68+
foo: [{ foo: 'bar' }],
69+
}
70+
const actions = {
71+
doThis,
72+
doThat,
73+
}
74+
const config = {
75+
state,
76+
actions,
77+
}
78+
79+
type Context = IContext<{
80+
state: typeof state
81+
actions: typeof actions
82+
}>
83+
84+
const app = new Overmind(config)
85+
86+
const useState = createStateHook<Context>()
87+
88+
const FooComponent: React.FunctionComponent = () => {
89+
const state = useState((state) => state.foo[0])
90+
renderCount++
91+
92+
return <h1>{state.foo}</h1>
93+
}
94+
95+
const tree = renderer
96+
.create(
97+
<Provider value={app}>
98+
<FooComponent />
99+
</Provider>
100+
)
101+
.toJSON()
102+
103+
expect(renderCount).toBe(1)
104+
105+
renderer.act(() => {
106+
app.actions.doThis()
107+
})
108+
109+
expect(renderCount).toBe(1)
110+
111+
renderer.act(() => {
112+
app.actions.doThat()
113+
})
114+
expect(renderCount).toBe(2)
115+
116+
// This is not showing the expected result, but logging the rendering does, so must be the
117+
// library messing it up
118+
expect(tree).toMatchSnapshot()
119+
})
58120
test('should allow using mocked Overmind', () => {
59121
let renderCount = 0
60122

packages/node_modules/overmind-react/src/index.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,9 @@ const useCurrentComponent = () => {
9595
: {}
9696
}
9797

98-
const useState = <Context extends IContext<any>>(): Context['state'] => {
98+
const useState = <Context extends IContext<any>>(
99+
cb?: (state: Context['state']) => any
100+
): Context['state'] => {
99101
const overmind = react.useContext(context) as Overmind<any>
100102

101103
if (!(overmind as any).mode) {
@@ -111,15 +113,17 @@ const useState = <Context extends IContext<any>>(): Context['state'] => {
111113
const { flushId, forceRerender } = useForceRerender()
112114

113115
if (!trackingRef.current) {
116+
const tree = (overmind as any).proxyStateTreeInstance.getTrackStateTree()
114117
trackingRef.current = {
115-
tree: (overmind as any).proxyStateTreeInstance.getTrackStateTree(),
118+
tree,
116119
hasUpdatedBeforeCommit: false,
117120
stopTrackingTask: unstable_scheduleCallback(
118121
unstable_getCurrentPriorityLevel(),
119122
() => {
120123
trackingRef.current.tree.stopTracking()
121124
}
122125
),
126+
state: cb ? cb(tree.state) : tree.state,
123127
}
124128
}
125129

@@ -212,7 +216,7 @@ const useState = <Context extends IContext<any>>(): Context['state'] => {
212216
})
213217
}
214218

215-
return trackingRef.current.tree.state
219+
return trackingRef.current.state
216220
}
217221

218222
const useActions = <Context extends IContext<any>>(): Context['actions'] => {
@@ -242,15 +246,18 @@ const useReaction = <Context extends IContext<any>>(): IReaction<Context> => {
242246
throwMissingContextError()
243247
}
244248

245-
return overmind.reaction
249+
return overmind.reaction as any
246250
}
247251

248-
export const createStateHook: <
249-
Context extends IContext<any>
250-
>() => () => Context['state'] = () => {
251-
return useState as any
252+
interface StateHook<Context extends IContext<any>> {
253+
(): Context['state']
254+
<T>(cb?: (state: Context['state']) => T): T
252255
}
253256

257+
export const createStateHook: <Context extends IContext<any>>() => StateHook<
258+
Context
259+
> = () => useState
260+
254261
export const createActionsHook: <
255262
Context extends IContext<any>
256263
>() => () => Context['actions'] = () => {

0 commit comments

Comments
 (0)