Skip to content

Commit 8aa0d3c

Browse files
feat(overmind): computed state now in state and shown in devtools
1 parent 92c40a2 commit 8aa0d3c

File tree

8 files changed

+100
-118
lines changed

8 files changed

+100
-118
lines changed

packages/demos/todomvc/src/app/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,13 @@ const app = new App(
1212
state,
1313
actions,
1414
providers,
15-
computed: {
16-
test: (foo: number) => (state) => state.count + foo,
17-
},
1815
},
1916
{
2017
devtools: 'localhost:1234',
2118
}
2219
)
2320

24-
export type Connect = TConnect<
25-
typeof app.state,
26-
typeof app.actions,
27-
typeof app.computed
28-
>
21+
export type Connect = TConnect<typeof app.state, typeof app.actions>
2922

3023
export const connect = app.connect
3124

packages/demos/todomvc/src/app/state.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { derived } from 'overmind'
1+
import { derived, computed } from 'overmind'
22

33
export type Todo = {
44
id: string
@@ -10,12 +10,14 @@ export type State = {
1010
todos: Todo[]
1111
newTodoTitle: string
1212
count: number
13+
testCount: (foo: number) => number
1314
}
1415

1516
const state: State = {
1617
todos: [],
1718
count: derived((state: State) => state.todos.length),
1819
newTodoTitle: '',
20+
testCount: computed((foo: number) => (state: State) => state.count + foo),
1921
}
2022

2123
export default state

packages/demos/todomvc/src/components/AddTodo/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { Wrapper, Input, Button, Form } from './elements'
44

55
const AddTodo: React.SFC<Connect> = ({ app }) => (
66
<Wrapper>
7-
{app.computed.test(5)}
7+
{app.state.testCount(5)}
88
<Form onSubmit={app.actions.addTodo}>
99
<Input
1010
placeholder="I need to..."

packages/node_modules/overmind-devtools/src/app/mutations.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ export const performMutationsByMessageType = (
104104
].components.push(id)
105105
break
106106
}
107-
case 'component:remove':
107+
case 'component:remove': {
108108
const id = `${clientMessage.data.componentId}_${
109109
clientMessage.data.componentInstanceId
110110
}`
@@ -114,13 +114,23 @@ export const performMutationsByMessageType = (
114114
state.apps[message.port].flushes.length - 1
115115
].components.push(id)
116116
break
117-
case 'derived':
117+
}
118+
case 'derived': {
118119
const appState = state.apps[message.port].state
119120
const path = clientMessage.data.path.split('.')
120121
const key = path.pop()
121122
const target = path.reduce((aggr, pathKey) => aggr[pathKey], appState)
122123
target[key] = clientMessage.data.value
123124
break
125+
}
126+
case 'computed': {
127+
const appState = state.apps[message.port].state
128+
const path = clientMessage.data.path.split('.')
129+
const key = path.pop()
130+
const target = path.reduce((aggr, pathKey) => aggr[pathKey], appState)
131+
target[key] = clientMessage.data
132+
break
133+
}
124134
}
125135
})
126136
}

packages/node_modules/overmind/src/computed.test.ts

Lines changed: 70 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,99 +2,107 @@ import App, { computed } from './'
22

33
describe('Computed', () => {
44
test('should instantiate app with computed', () => {
5+
type State = {
6+
foo: string
7+
test: (foo: number) => string
8+
}
9+
const state: State = {
10+
foo: 'bar',
11+
test: computed((foo: number) => (state: State) => state.foo + foo),
12+
}
513
const app = new App({
6-
state: {
7-
foo: 'bar',
8-
},
9-
computed: {
10-
test: (foo: number) => (state) => state.foo + foo,
11-
},
14+
state,
1215
})
13-
expect(app.computed.test(123)).toEqual('bar123')
16+
expect(app.state.test(123)).toEqual('bar123')
1417
})
1518
test('should not recalculate when not dirty', () => {
1619
let runCount = 0
20+
type State = {
21+
foo: string
22+
test: (foo: number) => string
23+
}
24+
const state: State = {
25+
foo: 'bar',
26+
test: computed((foo: number) => (state: State) => {
27+
runCount++
28+
return state.foo + foo
29+
}),
30+
}
1731
const app = new App({
18-
state: {
19-
foo: 'bar',
20-
},
21-
computed: {
22-
test: (foo: number) => (state) => {
23-
runCount++
24-
return state.foo + foo
25-
},
26-
},
32+
state,
2733
})
28-
app.computed.test(123)
29-
app.computed.test(123)
34+
app.state.test(123)
35+
app.state.test(123)
3036
expect(runCount).toEqual(1)
3137
})
3238
test('should create new cache entry when args change', () => {
3339
let runCount = 0
40+
type State = {
41+
foo: string
42+
test: (foo: number) => string
43+
}
44+
const state: State = {
45+
foo: 'bar',
46+
test: computed((foo: number) => (state: State) => {
47+
runCount++
48+
return state.foo + foo
49+
}),
50+
}
3451
const app = new App({
35-
state: {
36-
foo: 'bar',
37-
},
38-
computed: {
39-
test: (foo: number) => (state) => {
40-
runCount++
41-
return state.foo + foo
42-
},
43-
},
52+
state,
4453
})
45-
app.computed.test(123)
46-
app.computed.test(321)
54+
app.state.test(123)
55+
app.state.test(321)
4756
expect(runCount).toEqual(2)
4857
})
49-
test.only('should flag as dirty when state changes', () => {
58+
test('should flag as dirty when state changes', () => {
5059
let runCount = 0
60+
type State = {
61+
foo: string
62+
test: (foo: number) => string
63+
}
64+
const state: State = {
65+
foo: 'bar',
66+
test: computed((foo: number) => (state: State) => {
67+
runCount++
68+
return state.foo + foo
69+
}),
70+
}
5171
const app = new App({
52-
state: {
53-
foo: 'bar',
54-
},
55-
computed: {
56-
test: (foo: number) => (state) => {
57-
runCount++
58-
return state.foo + foo
59-
},
60-
},
72+
state,
6173
actions: (action) => ({
6274
changeFoo: action().mutation((_, state) => (state.foo = 'bar2')),
6375
}),
6476
})
65-
app.computed.test(123)
77+
app.state.test(123)
6678
app.actions.changeFoo()
67-
expect(app.computed.test(123)).toEqual('bar2123')
79+
expect(app.state.test(123)).toEqual('bar2123')
6880
expect(runCount).toEqual(2)
6981
})
7082
test('should use factory to adjust cache limit', () => {
7183
let runCount = 0
7284
type State = {
7385
foo: string
86+
test: (foo: number) => string
87+
}
88+
const state: State = {
89+
foo: 'bar',
90+
test: computed(
91+
(foo: number) => (state: State) => {
92+
runCount++
93+
return state.foo + foo
94+
},
95+
{
96+
cacheLimit: 1,
97+
}
98+
),
7499
}
75100
const app = new App({
76-
state: {
77-
foo: 'bar',
78-
},
79-
computed: {
80-
test: computed(
81-
(foo: number) => (state: State) => {
82-
runCount++
83-
return state.foo + foo
84-
},
85-
{
86-
cacheLimit: 1,
87-
}
88-
),
89-
},
101+
state,
90102
})
91-
app.computed.test(123)
92-
app.computed.test(432)
93-
app.computed.test(123)
103+
app.state.test(123)
104+
app.state.test(432)
105+
app.state.test(123)
94106
expect(runCount).toEqual(3)
95107
})
96108
})
97-
98-
/*
99-
- Should expose to actions as provider
100-
*/

packages/node_modules/overmind/src/computed.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ export class Computed {
2020
constructor(cb, options: ComputedOptions = {}) {
2121
this.cb = cb
2222
this.cacheLimit = options.cacheLimit || this.cacheLimit
23+
return this.evaluate.bind(this)
2324
}
2425
evaluate(actionChain, proxyStateTree: ProxyStateTree, path) {
2526
return (config) => {
@@ -84,6 +85,6 @@ export class Computed {
8485
export default function computed<Config, NewValue>(
8586
cb: (config: Config) => (state: object) => NewValue,
8687
options?: ComputedOptions
87-
): (config: Config) => (state: object) => NewValue {
88+
): (config: Config) => NewValue {
8889
return new Computed(cb, options) as any
8990
}

packages/node_modules/overmind/src/index.ts

Lines changed: 3 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,14 @@ import { ActionChain } from 'action-chain'
22
import ProxyStateTree from 'proxy-state-tree'
33
import Devtools, { Message, safeValue } from './Devtools'
44
import Action, { IValueAction, INoValueAction } from './Action'
5-
import { Computed } from './computed'
65
export { default as compose } from './compose'
76
export { default as derived } from './derived'
87
export { default as computed } from './computed'
98

10-
type Configuration<State, Providers, Actions, Computed> = {
9+
type Configuration<State, Providers, Actions> = {
1110
state?: State
1211
providers?: Providers
1312
actions?: Actions
14-
computed?: Computed
1513
}
1614

1715
type Options = {
@@ -39,10 +37,7 @@ export default class App<
3937
| {
4038
[namespace: string]: ActionsCallback<Providers, State>
4139
}
42-
| ActionsCallback<Providers, State>,
43-
Computed extends {
44-
[key: string]: (...args: any[]) => (state: State) => any
45-
}
40+
| ActionsCallback<Providers, State>
4641
> {
4742
private proxyStateTree: ProxyStateTree
4843
devtools: Devtools
@@ -54,9 +49,8 @@ export default class App<
5449
? ReturnType<Actions>
5550
: any
5651
state: State
57-
computed: Computed
5852
constructor(
59-
configuration: Configuration<State, Providers, Actions, Computed>,
53+
configuration: Configuration<State, Providers, Actions>,
6054
options: Options = {}
6155
) {
6256
const proxyStateTree = new ProxyStateTree(configuration.state || {}, {
@@ -115,24 +109,6 @@ export default class App<
115109
}),
116110
{}
117111
) as any)
118-
this.computed = Object.keys(configuration.computed || {}).reduce(
119-
(aggr, key) =>
120-
Object.assign(aggr, {
121-
[key]:
122-
configuration.computed[key] instanceof Computed
123-
? (configuration.computed[key] as any).evaluate(
124-
actionChain,
125-
proxyStateTree,
126-
key
127-
)
128-
: new Computed(configuration.computed[key]).evaluate(
129-
actionChain,
130-
proxyStateTree,
131-
key
132-
),
133-
}),
134-
{}
135-
) as Computed
136112
this.proxyStateTree = proxyStateTree
137113

138114
if (options.devtools && typeof window !== 'undefined') {

0 commit comments

Comments
 (0)