Skip to content

Commit 4051135

Browse files
Merge pull request cerebral#21 from cerebral/derivedMessagesToDevtools
Derived messages to devtools
2 parents 30e9937 + aa14fdb commit 4051135

File tree

10 files changed

+75
-10
lines changed

10 files changed

+75
-10
lines changed

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

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ export default (action: Action) => ({
1111
addTodo: action<React.FormEvent>()
1212
.do(helpers.preventEventDefault)
1313
.mutation(mutations.addTodo)
14-
.mutation(mutations.clearNewTodoTitle)
15-
.filter((_, { state }) => state.todos.length > 2)
16-
.map(() => Promise.resolve())
17-
.mutation((_, state) => (state.todos[2].title = 'mihihihi')),
14+
.mutation(mutations.clearNewTodoTitle),
1815
toggleCompleted: action<Todo>().mutation(mutations.toggleCompleted),
1916
})

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { derived } from 'overmind'
2+
13
export type Todo = {
24
id: string
35
title: string
@@ -7,10 +9,12 @@ export type Todo = {
79
export type State = {
810
todos: Todo[]
911
newTodoTitle: string
12+
count: number
1013
}
1114

1215
const state: State = {
1316
todos: [],
17+
count: derived((state: State) => state.todos.length),
1418
newTodoTitle: '',
1519
}
1620

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

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

55
const AddTodo: React.SFC<Connect> = ({ app }) => (
66
<Wrapper>
7+
{app.state.count}
78
<Form onSubmit={app.actions.addTodo}>
89
<Input
910
placeholder="I need to..."

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ export const performMutationsByMessageType = (
114114
state.apps[message.port].flushes.length - 1
115115
].components.push(id)
116116
break
117+
case 'derived':
118+
const appState = state.apps[message.port].state
119+
const path = clientMessage.data.path.split('.')
120+
const key = path.pop()
121+
const target = path.reduce((aggr, pathKey) => aggr[pathKey], appState)
122+
target[key] = clientMessage.data.value
123+
break
117124
}
118125
})
119126
}

packages/node_modules/overmind/src/derived.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@ class Derived {
66
value: any
77
cb: (state: object) => void
88
paths: Set<string>
9+
updateCount: number
910
constructor(cb) {
1011
this.isDirty = true
1112
this.proxyStateTreeListener = null
1213
this.value = null
1314
this.cb = cb
15+
this.updateCount = 0
1416
return this.evaluate.bind(this)
1517
}
16-
evaluate(proxyStateTree: ProxyStateTree) {
18+
evaluate(actionChain, proxyStateTree: ProxyStateTree, path) {
1719
if (this.isDirty) {
1820
const trackId = proxyStateTree.startPathsTracking()
1921
this.value = this.cb(proxyStateTree.get())
@@ -29,6 +31,13 @@ class Derived {
2931
}
3032
)
3133
}
34+
actionChain.emit('derived', {
35+
path,
36+
paths: Array.from(this.paths),
37+
updateCount: this.updateCount,
38+
value: this.value,
39+
})
40+
this.updateCount++
3241
}
3342

3443
// Tracks the paths for the consumer of this derived value

packages/node_modules/overmind/src/index.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ export default class App<
5555
configuration: Configuration<State, Providers, Actions>,
5656
options: Options = {}
5757
) {
58-
const proxyStateTree = new ProxyStateTree(configuration.state || {})
58+
const proxyStateTree = new ProxyStateTree(configuration.state || {}, {
59+
dynamicWrapper: (proxyStateTree, path, func) =>
60+
func(actionChain, proxyStateTree, path),
61+
})
5962
const actionChain = actionChainFactory(
6063
Object.assign(
6164
{
@@ -171,6 +174,12 @@ export default class App<
171174
data,
172175
})
173176
)
177+
actionChain.on('derived', (data) =>
178+
devtools.send({
179+
type: 'derived',
180+
data,
181+
})
182+
)
174183
this.devtools = devtools
175184
}
176185
trackState() {

packages/node_modules/proxy-state-tree/README.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,18 @@ const tree = new ProxyStateTree({
138138
})
139139
```
140140

141-
The allows you to easily extend functionality with for example a computed concept that lives in the tree, as you can see in this [codesandbox](https://codesandbox.io/s/xnv45zmkz).
141+
The allows you to easily extend functionality with for example a computed concept that lives in the tree, as you can see in this [codesandbox](https://codesandbox.io/s/xnv45zmkz).
142+
143+
You can inject a wrapper around this function by:
144+
145+
```js
146+
import ProxyStateTree from 'proxy-state-tree'
147+
148+
const tree = new ProxyStateTree({
149+
foo: (foo, proxyStateTree, path) => {}
150+
}, {
151+
dynamicWrapper: (proxyStateTree, path, func) => func('foo', proxyStateTree, path)
152+
})
153+
```
154+
155+
This helps you expose library entities to these functions.

packages/node_modules/proxy-state-tree/src/index.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,23 @@ describe('FUNCTIONS', () => {
369369
}
370370
const tree = new ProxyStateTree(state)
371371

372+
expect(tree.get().foo).toBe('bar')
373+
})
374+
test('should be able to inject a wrapper around functions', () => {
375+
const state = {
376+
foo: (foo, proxyStateTree, path) => {
377+
expect(foo).toBe('foo')
378+
expect(proxyStateTree).toBe(tree)
379+
expect(path).toEqual('foo')
380+
381+
return 'bar'
382+
},
383+
}
384+
const tree = new ProxyStateTree(state, {
385+
dynamicWrapper: (proxyStateTree, path, func) =>
386+
func('foo', proxyStateTree, path),
387+
})
388+
372389
expect(tree.get().foo).toBe('bar')
373390
})
374391
})

packages/node_modules/proxy-state-tree/src/index.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import proxify, { IS_PROXY, STATUS } from './proxify'
22
const isPlainObject = require('is-plain-object')
33

44
export type Options = {
5-
devmode: boolean
5+
devmode?: boolean
6+
dynamicWrapper?: Function
67
}
78

89
type Mutation = {
@@ -21,11 +22,15 @@ class ProxyStateTree {
2122
paths: Set<string>[]
2223
status: STATUS
2324
proxy: any
24-
constructor(state: object, options: Options = { devmode: true }) {
25+
constructor(state: object, options: Options = {}) {
2526
if (!isPlainObject(state)) {
2627
throw new Error('You have to pass a plain object to the Proxy State Tree')
2728
}
2829

30+
if (typeof options.devmode === 'undefined') {
31+
options.devmode = true
32+
}
33+
2934
this.state = state
3035
this.options = options
3136
this.pathDependencies = {}

packages/node_modules/proxy-state-tree/src/proxify.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,9 @@ function createObjectProxy(tree, value, path) {
112112
}
113113

114114
if (typeof targetValue === 'function') {
115-
return targetValue(tree, nestedPath)
115+
return tree.options.dynamicWrapper
116+
? tree.options.dynamicWrapper(tree, nestedPath, targetValue)
117+
: targetValue(tree, nestedPath)
116118
}
117119

118120
if (targetValue === undefined) {

0 commit comments

Comments
 (0)