Skip to content

Commit 7a3a474

Browse files
Merge pull request cerebral#213 from cerebral/angularfixes
Angularfixes
2 parents b689796 + bf8065e commit 7a3a474

File tree

10 files changed

+275
-193
lines changed

10 files changed

+275
-193
lines changed
Lines changed: 74 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,146 +1,90 @@
1-
import { EventType, Overmind, TApp, Configuration } from 'overmind'
1+
// import { Injectable } from "@angular/core"
2+
import { Overmind, EventType } from 'overmind'
3+
import { BehaviorSubject, Observable } from 'rxjs'
4+
import { map } from 'rxjs/operators'
25

3-
// @ts-ignore
4-
import { NgZone } from '@angular/core'
5-
import { IMutation } from 'proxy-state-tree'
6-
7-
export interface IConnect<Config extends Configuration> {
8-
state: TApp<Config>['state']
9-
actions: TApp<Config>['actions']
10-
effects: TApp<Config>['effects']
11-
addMutationListener: (cb: (mutation: IMutation) => void) => () => void
12-
}
6+
const IS_PRODUCTION = process.env.NODE_ENV === 'production'
137

148
let nextComponentId = 0
159

16-
export const createConnect = <A extends Overmind<any>>(overmind: A) => (
17-
propsCallback?: (
18-
overmind: {
19-
state: A['state']
20-
actions: A['actions']
21-
effects: A['effects']
22-
}
23-
) => object
24-
) => {
10+
export const Track = (Component) => {
11+
if (IS_PRODUCTION) {
12+
return
13+
}
14+
2515
const componentId = nextComponentId++
2616
let componentInstanceId = 0
2717

28-
return function(target: any) {
29-
const targetNgOnInit = target.prototype.ngOnInit
30-
const targetNgDoCheck = target.prototype.ngDoCheck
31-
const targetNgAfterContentInit = target.prototype.ngAfterContentInit
32-
const targetNgAfterViewInit = target.prototype.ngAfterViewInit
33-
const targetNgAfterViewChecked = target.prototype.ngAfterViewChecked
34-
35-
target.prototype.ngOnInit = function() {
36-
const ngZ = new NgZone({ enableLongStackTrace: false })
37-
38-
this.__tree = (overmind as any).proxyStateTree.getTrackStateTree()
39-
this.__currentFlushId = 0
40-
this.overmind = {
41-
state: this.__tree.state,
42-
actions: overmind.actions,
43-
effects: overmind.effects,
44-
addMutationListener: overmind.addMutationListener,
45-
}
46-
if (propsCallback) {
47-
Object.assign(
48-
this,
49-
propsCallback({
50-
state: this.__tree.state,
51-
actions: overmind.actions,
52-
effects: overmind.effects,
53-
})
54-
)
55-
}
56-
this.__shouldUpdatePaths = false
57-
this.__componentInstanceId = componentInstanceId++
58-
this.__onUpdate = (mutations, paths, flushId) => {
59-
this.__currentFlushId = flushId
60-
61-
if (this.cdr) {
62-
this.cdr.markForCheck()
63-
}
64-
ngZ.run(() => {})
65-
}
66-
67-
if (targetNgOnInit) {
68-
targetNgOnInit.call(this)
69-
}
70-
71-
if (
72-
!this.cdr &&
73-
(!target['__annotations__'][0] ||
74-
target['__annotations__'][0].changeDetection === 0)
75-
) {
76-
throw new Error(
77-
'overmind-angular ERROR: You have to inject the ChangeDetectionRef as "cdr" on the component. In the constructor, add argument: "private cdr: ChangeDetectorRef" '
78-
)
79-
}
80-
}
18+
function findService(target) {
19+
return Object.keys(target).find((key) => target[key] instanceof Service)
20+
}
8121

82-
target.prototype.ngAfterContentInit = function() {
83-
this.__tree.track(this.__onUpdate)
22+
const targetNgOnInit = Component.prototype.ngOnInit
23+
Component.prototype.ngOnInit = function() {
24+
const service = this[findService(this)]
25+
service.addComponent({
26+
componentId,
27+
componentInstanceId: componentInstanceId++,
28+
name: Component.name,
29+
})
8430

85-
if (targetNgAfterContentInit) {
86-
targetNgAfterContentInit.call(this)
87-
}
88-
}
31+
targetNgOnInit && targetNgOnInit.call(this)
32+
}
33+
}
8934

90-
target.prototype.ngAfterViewInit = function() {
91-
overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, {
92-
componentId,
93-
componentInstanceId: this.__componentInstanceId,
94-
name: this.constructor.name || '',
95-
paths: Array.from(this.__tree.pathDependencies) as any,
35+
export class Service<App extends Overmind<any>> {
36+
private tree: any
37+
private state$: Observable<any>
38+
private subject: BehaviorSubject<any>
39+
private overmind: App
40+
private componentDetails: any
41+
actions: App['actions']
42+
effects: App['effects']
43+
addMutationListener: App['addMutationListener']
44+
constructor(overmind: App) {
45+
this.tree = (overmind as any).proxyStateTree.getTrackStateTreeWithProxifier()
46+
this.subject = new BehaviorSubject(this.tree.state)
47+
this.state$ = this.subject.asObservable()
48+
this.overmind = overmind
49+
50+
this.actions = this.overmind.actions
51+
this.addMutationListener = this.overmind.addMutationListener
52+
53+
this.tree.track(this.onUpdate)
54+
}
55+
private addComponent(componentDetails) {
56+
this.componentDetails = componentDetails
57+
this.overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, {
58+
componentId: componentDetails.componentId,
59+
componentInstanceId: componentDetails.componentInstanceId,
60+
name: componentDetails.name,
61+
paths: Array.from(this.tree.pathDependencies) as any,
62+
})
63+
}
64+
private onUpdate = (mutations, paths, flushId) => {
65+
this.tree.track(this.onUpdate)
66+
this.subject.next(this.tree.state)
67+
if (this.componentDetails) {
68+
this.overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, {
69+
componentId: this.componentDetails.componentId,
70+
componentInstanceId: this.componentDetails.componentInstanceId,
71+
name: this.componentDetails.name,
72+
paths: Array.from(this.tree.pathDependencies) as any,
73+
flushId,
9674
})
97-
98-
if (targetNgAfterViewInit) {
99-
targetNgAfterViewInit.call(this)
100-
}
101-
}
102-
103-
target.prototype.ngDoCheck = function() {
104-
if (this.__shouldUpdatePaths) {
105-
this.__tree.track(this.__onUpdate)
106-
}
107-
if (targetNgDoCheck) {
108-
targetNgDoCheck.call(this)
109-
}
110-
}
111-
112-
target.prototype.ngAfterViewChecked = function() {
113-
if (this.__shouldUpdatePaths) {
114-
this.__shouldUpdatePaths = false
115-
overmind.eventHub.emitAsync(EventType.COMPONENT_UPDATE, {
116-
componentId,
117-
componentInstanceId: this.__componentInstanceId,
118-
name: this.constructor.name || '',
119-
paths: Array.from(this.__tree.pathDependencies) as any,
120-
flushId: this.__currentFlushId,
121-
})
122-
}
123-
if (targetNgAfterViewChecked) {
124-
targetNgAfterViewChecked.call(this)
125-
}
12675
}
127-
128-
let targetNgOnDestroy = target.prototype.ngOnDestroy
129-
130-
target.prototype.ngOnDestroy = function() {
131-
overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
132-
componentId,
133-
componentInstanceId: this.__componentInstanceId,
134-
name: this.constructor.name || '',
76+
}
77+
private ngOnDestroy() {
78+
;(this.overmind as any).proxyStateTree.disposeTree(this.tree)
79+
if (this.componentDetails) {
80+
this.overmind.eventHub.emitAsync(EventType.COMPONENT_REMOVE, {
81+
componentId: this.componentDetails.componentId,
82+
componentInstanceId: this.componentDetails.componentInstanceId,
83+
name: this.componentDetails.name,
13584
})
136-
const anyOvermind = overmind as any
137-
anyOvermind.proxyStateTree.disposeTree(this.__tree)
138-
139-
if (targetNgOnDestroy) {
140-
targetNgOnDestroy.call(this)
141-
}
14285
}
143-
144-
return target
86+
}
87+
select(expr: any) {
88+
return this.state$.pipe(map((value) => expr(value)))
14589
}
14690
}

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

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ export const createHook = <Config extends Configuration>(
9494
},
9595
[]
9696
)
97+
98+
useLayoutEffect(() => tree.stopTracking())
9799
} else {
98100
const [componentInstanceId] = useState<any>(
99101
() => currentComponentInstanceId++
@@ -110,6 +112,8 @@ export const createHook = <Config extends Configuration>(
110112
})
111113
})
112114

115+
useLayoutEffect(() => tree.stopTracking())
116+
113117
useEffect(() => {
114118
overmind.eventHub.emitAsync(EventType.COMPONENT_ADD, {
115119
componentId: component.__componentId,
@@ -158,9 +162,10 @@ export const createConnect = <A extends Overmind<Configuration>>(
158162
if (isClassComponent) {
159163
const originalRender = component.prototype.render
160164
component.prototype.render = function() {
161-
this.props.overmind &&
162-
this.props.overmind.tree.track(this.props.overmind.onUpdate)
163-
return originalRender.call(this)
165+
return this.props.overmind.tree.trackScope(
166+
() => originalRender.call(this),
167+
this.props.overmind.onUpdate
168+
)
164169
}
165170
}
166171

@@ -206,12 +211,17 @@ export const createConnect = <A extends Overmind<Configuration>>(
206211
} as any)
207212
}
208213

209-
this.tree.track(this.onUpdate)
210-
211-
return createElement(component, {
212-
...this.props,
213-
overmind: this.state.overmind,
214-
} as any)
214+
return createElement(
215+
(...args) =>
216+
this.tree.trackScope(
217+
() => (component as any)(...args),
218+
this.onUpdate
219+
),
220+
{
221+
...this.props,
222+
overmind: this.state.overmind,
223+
} as any
224+
)
215225
}
216226
}
217227

@@ -282,13 +292,17 @@ export const createConnect = <A extends Overmind<Configuration>>(
282292
overmind: this.state.overmind,
283293
} as any)
284294
}
285-
286-
this.tree.track(this.onUpdate)
287-
288-
return createElement(component, {
289-
...this.props,
290-
overmind: this.state.overmind,
291-
} as any)
295+
return createElement(
296+
(...args) =>
297+
this.tree.trackScope(
298+
() => (component as any)(...args),
299+
this.onUpdate
300+
),
301+
{
302+
...this.props,
303+
overmind: this.state.overmind,
304+
} as any
305+
)
292306
}
293307
}
294308

0 commit comments

Comments
 (0)