cx 26.7.1 → 26.7.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/ui/Cx.d.ts +3 -5
- package/build/ui/Cx.d.ts.map +1 -1
- package/build/ui/Cx.js +48 -44
- package/build/ui/Restate.d.ts +0 -6
- package/build/ui/Restate.d.ts.map +1 -1
- package/build/ui/Restate.js +1 -2
- package/dist/manifest.js +784 -784
- package/dist/ui.js +66 -58
- package/package.json +1 -1
- package/src/ui/Cx.tsx +422 -427
- package/src/ui/Restate.tsx +217 -226
package/src/ui/Cx.tsx
CHANGED
|
@@ -1,427 +1,422 @@
|
|
|
1
|
-
/** @jsxImportSource react */
|
|
2
|
-
|
|
3
|
-
import { Widget, VDOM, getContent } from "./Widget";
|
|
4
|
-
import { Instance } from "./Instance";
|
|
5
|
-
import { RenderingContext } from "./RenderingContext";
|
|
6
|
-
import { debug, appDataFlag } from "../util/Debug";
|
|
7
|
-
import { Timing, now, appLoopFlag, vdomRenderFlag } from "../util/Timing";
|
|
8
|
-
import { isBatchingUpdates, notifyBatchedUpdateStarting, notifyBatchedUpdateCompleted } from "./batchUpdates";
|
|
9
|
-
import { shallowEquals } from "../util/shallowEquals";
|
|
10
|
-
import { PureContainer } from "./PureContainer";
|
|
11
|
-
import { onIdleCallback } from "../util/onIdleCallback";
|
|
12
|
-
import { getCurrentCulture, pushCulture, popCulture, CultureInfo, ResolvedCultureInfo } from "./Culture";
|
|
13
|
-
import { View } from "../data/View";
|
|
14
|
-
import { Config } from "./Prop";
|
|
15
|
-
|
|
16
|
-
export interface CxProps {
|
|
17
|
-
widget?: Config;
|
|
18
|
-
items?: Config;
|
|
19
|
-
store?: View;
|
|
20
|
-
instance?: Instance;
|
|
21
|
-
parentInstance?: Instance;
|
|
22
|
-
subscribe?: boolean;
|
|
23
|
-
immediate?: boolean;
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
this.
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.
|
|
140
|
-
this.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
if (this.
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this.
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
if (
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
this.
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
if (this.props.
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
if (
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
this.timings.afterRender = now();
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
this.
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
this.
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
this.timings.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
componentWillUnmount(): void {
|
|
424
|
-
let { instance } = this.props;
|
|
425
|
-
if ((instance as any).destroyTracked) (instance as any).destroy();
|
|
426
|
-
}
|
|
427
|
-
}
|
|
1
|
+
/** @jsxImportSource react */
|
|
2
|
+
|
|
3
|
+
import { Widget, VDOM, getContent } from "./Widget";
|
|
4
|
+
import { Instance } from "./Instance";
|
|
5
|
+
import { RenderingContext } from "./RenderingContext";
|
|
6
|
+
import { debug, appDataFlag } from "../util/Debug";
|
|
7
|
+
import { Timing, now, appLoopFlag, vdomRenderFlag } from "../util/Timing";
|
|
8
|
+
import { isBatchingUpdates, notifyBatchedUpdateStarting, notifyBatchedUpdateCompleted } from "./batchUpdates";
|
|
9
|
+
import { shallowEquals } from "../util/shallowEquals";
|
|
10
|
+
import { PureContainer } from "./PureContainer";
|
|
11
|
+
import { onIdleCallback } from "../util/onIdleCallback";
|
|
12
|
+
import { getCurrentCulture, pushCulture, popCulture, CultureInfo, ResolvedCultureInfo } from "./Culture";
|
|
13
|
+
import { View } from "../data/View";
|
|
14
|
+
import { Config } from "./Prop";
|
|
15
|
+
|
|
16
|
+
export interface CxProps {
|
|
17
|
+
widget?: Config;
|
|
18
|
+
items?: Config;
|
|
19
|
+
store?: View;
|
|
20
|
+
instance?: Instance;
|
|
21
|
+
parentInstance?: Instance;
|
|
22
|
+
subscribe?: boolean;
|
|
23
|
+
immediate?: boolean;
|
|
24
|
+
deferredUntilIdle?: boolean;
|
|
25
|
+
idleTimeout?: number;
|
|
26
|
+
options?: any;
|
|
27
|
+
onError?: (error: Error, instance: Instance, info: any) => void;
|
|
28
|
+
params?: any;
|
|
29
|
+
contentFactory?: (props: { children: any }) => any;
|
|
30
|
+
cultureInfo?: ResolvedCultureInfo;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface CxState {
|
|
34
|
+
deferToken: number;
|
|
35
|
+
data?: any;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export class Cx extends VDOM.Component<CxProps, CxState> {
|
|
39
|
+
widget: Widget;
|
|
40
|
+
store: View;
|
|
41
|
+
parentInstance?: Instance;
|
|
42
|
+
instance?: Instance;
|
|
43
|
+
flags: { preparing?: boolean; dirty?: boolean; rendering?: boolean };
|
|
44
|
+
renderCount: number;
|
|
45
|
+
unsubscribe?: () => void;
|
|
46
|
+
componentDidCatch?: (error: Error, info: any) => void;
|
|
47
|
+
forceUpdateCallback: () => void;
|
|
48
|
+
deferCounter: number;
|
|
49
|
+
pendingUpdateTimer?: NodeJS.Timeout;
|
|
50
|
+
unsubscribeIdleRequest?: () => void;
|
|
51
|
+
// 0 when no synchronous setState is in flight; >0 while one is pending (re-entrancy guard for update())
|
|
52
|
+
stateUpdateDepth: number = 0;
|
|
53
|
+
|
|
54
|
+
constructor(props: CxProps) {
|
|
55
|
+
super(props);
|
|
56
|
+
|
|
57
|
+
if (props.instance) {
|
|
58
|
+
this.widget = (props.instance as any).widget;
|
|
59
|
+
this.store = (props.instance as any).store;
|
|
60
|
+
} else {
|
|
61
|
+
this.widget = PureContainer.create({ items: props.widget || props.items });
|
|
62
|
+
|
|
63
|
+
if (props.parentInstance) {
|
|
64
|
+
this.parentInstance = props.parentInstance;
|
|
65
|
+
this.store = props.store || (this.parentInstance as any).store;
|
|
66
|
+
} else {
|
|
67
|
+
this.parentInstance = new Instance(this.widget, "0", undefined, props.store);
|
|
68
|
+
this.store = props.store!;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!this.store) throw new Error("Cx component requires a store.");
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
this.state = {
|
|
75
|
+
deferToken: 0,
|
|
76
|
+
data: props.subscribe ? this.store.getData() : null,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
if (props.subscribe) {
|
|
80
|
+
this.unsubscribe = this.store.subscribe(this.update.bind(this));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.onStateUpdateCompleted = this.onStateUpdateCompleted.bind(this);
|
|
84
|
+
|
|
85
|
+
this.flags = {};
|
|
86
|
+
this.renderCount = 0;
|
|
87
|
+
|
|
88
|
+
if (props.onError) this.componentDidCatch = this.componentDidCatchHandler.bind(this);
|
|
89
|
+
|
|
90
|
+
this.forceUpdateCallback = this.forceUpdate.bind(this);
|
|
91
|
+
|
|
92
|
+
this.deferCounter = 0;
|
|
93
|
+
this.waitForIdle();
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
UNSAFE_componentWillReceiveProps(props: CxProps): void {
|
|
97
|
+
let newStore = props.instance
|
|
98
|
+
? (props.instance as any).store
|
|
99
|
+
: props.store
|
|
100
|
+
? props.store
|
|
101
|
+
: (props.parentInstance as any).store;
|
|
102
|
+
|
|
103
|
+
if (newStore != this.store) {
|
|
104
|
+
this.store = newStore;
|
|
105
|
+
if (this.unsubscribe) this.unsubscribe();
|
|
106
|
+
if (props.subscribe) this.unsubscribe = this.store.subscribe(this.update.bind(this));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (props.subscribe) {
|
|
110
|
+
let data = this.store.getData();
|
|
111
|
+
if (data !== this.state.data) {
|
|
112
|
+
this.waitForIdle();
|
|
113
|
+
this.setState({ data });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
getInstance(): Instance {
|
|
119
|
+
if (this.props.instance) return this.props.instance;
|
|
120
|
+
|
|
121
|
+
if (this.instance && this.instance.widget === this.widget) {
|
|
122
|
+
if (this.instance.parentStore != this.store) this.instance.setParentStore(this.store);
|
|
123
|
+
return this.instance;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (this.widget && this.parentInstance)
|
|
127
|
+
return (this.instance = this.parentInstance.getDetachedChild(this.widget, "0", this.store));
|
|
128
|
+
|
|
129
|
+
throw new Error("Could not resolve a widget instance in the Cx component.");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
render() {
|
|
133
|
+
if (this.props.deferredUntilIdle && this.state.deferToken < this.deferCounter) return null;
|
|
134
|
+
|
|
135
|
+
let cultureInfo = this.props.cultureInfo ?? getCurrentCulture();
|
|
136
|
+
|
|
137
|
+
return (
|
|
138
|
+
<CxContext
|
|
139
|
+
instance={this.getInstance()}
|
|
140
|
+
flags={this.flags}
|
|
141
|
+
options={this.props.options}
|
|
142
|
+
buster={++this.renderCount}
|
|
143
|
+
contentFactory={this.props.contentFactory}
|
|
144
|
+
forceUpdate={this.forceUpdateCallback}
|
|
145
|
+
cultureInfo={cultureInfo}
|
|
146
|
+
/>
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
componentDidMount(): void {
|
|
151
|
+
this.componentDidUpdate();
|
|
152
|
+
|
|
153
|
+
if (this.props.options && this.props.options.onPipeUpdate)
|
|
154
|
+
this.props.options.onPipeUpdate(this.update.bind(this));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
componentDidUpdate(): void {
|
|
158
|
+
if (this.flags.dirty) {
|
|
159
|
+
this.update();
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
update(): void {
|
|
164
|
+
let data = this.store.getData();
|
|
165
|
+
debug(appDataFlag, data);
|
|
166
|
+
if (this.flags.preparing) this.flags.dirty = true;
|
|
167
|
+
// Synchronous path (while batching, or for `immediate` instances). At most one setState may be in flight
|
|
168
|
+
// per Cx: if one is already pending (stateUpdateDepth != 0) skip issuing another. Re-entrant setStates
|
|
169
|
+
// nested deep -- e.g. a large initial render that writes to the store while it renders -- are what trip
|
|
170
|
+
// React's "Maximum update depth exceeded"; coalescing them into a single in-flight update avoids that.
|
|
171
|
+
// The pending update's completion callback re-reads the store and renders again if it changed
|
|
172
|
+
// (see onStateUpdateCompleted), so no change is dropped.
|
|
173
|
+
else if (this.props.immediate || isBatchingUpdates()) {
|
|
174
|
+
if (this.stateUpdateDepth == 0) {
|
|
175
|
+
this.stateUpdateDepth = 1;
|
|
176
|
+
notifyBatchedUpdateStarting();
|
|
177
|
+
this.setState({ data: data }, this.onStateUpdateCompleted);
|
|
178
|
+
}
|
|
179
|
+
} else {
|
|
180
|
+
// standard mode: coalesce sequential store commands into a single deferred update
|
|
181
|
+
this.scheduleStateUpdate();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
scheduleStateUpdate() {
|
|
186
|
+
if (!this.pendingUpdateTimer) {
|
|
187
|
+
notifyBatchedUpdateStarting();
|
|
188
|
+
this.pendingUpdateTimer = setTimeout(() => {
|
|
189
|
+
delete this.pendingUpdateTimer;
|
|
190
|
+
// read fresh data at fire time so the coalesced update renders the latest store state
|
|
191
|
+
this.setState({ data: this.store.getData() }, notifyBatchedUpdateCompleted);
|
|
192
|
+
}, 0);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Completion callback for the synchronous setState above. If the store changed while that update was
|
|
197
|
+
// rendering -- i.e. the render itself wrote to the store, as happens throughout a large initial render --
|
|
198
|
+
// render once more with the latest data, keeping this callback armed; otherwise the burst has settled, so
|
|
199
|
+
// clear the in-flight flag and report completion. Re-arming coalesces until the store reaches a fixpoint;
|
|
200
|
+
// a genuinely non-converging update loop is still caught by React's own max-update-depth guard.
|
|
201
|
+
onStateUpdateCompleted() {
|
|
202
|
+
let latestData = this.store.getData();
|
|
203
|
+
notifyBatchedUpdateCompleted();
|
|
204
|
+
if (this.state.data === latestData) {
|
|
205
|
+
this.stateUpdateDepth = 0;
|
|
206
|
+
} else {
|
|
207
|
+
this.stateUpdateDepth++;
|
|
208
|
+
if (this.stateUpdateDepth < 20 && isBatchingUpdates())
|
|
209
|
+
this.setState({ data: latestData }, this.onStateUpdateCompleted);
|
|
210
|
+
else this.scheduleStateUpdate();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
waitForIdle(): void {
|
|
215
|
+
if (!this.props.deferredUntilIdle) return;
|
|
216
|
+
|
|
217
|
+
if (this.unsubscribeIdleRequest) this.unsubscribeIdleRequest();
|
|
218
|
+
|
|
219
|
+
let token = ++this.deferCounter;
|
|
220
|
+
this.unsubscribeIdleRequest = onIdleCallback(
|
|
221
|
+
() => {
|
|
222
|
+
this.setState({ deferToken: token }, this.onStateUpdateCompleted);
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
timeout: this.props.idleTimeout || 30000,
|
|
226
|
+
},
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
componentWillUnmount(): void {
|
|
231
|
+
if (this.pendingUpdateTimer) clearTimeout(this.pendingUpdateTimer);
|
|
232
|
+
if (this.unsubscribeIdleRequest) this.unsubscribeIdleRequest();
|
|
233
|
+
if (this.unsubscribe) this.unsubscribe();
|
|
234
|
+
if (this.props.options && this.props.options.onPipeUpdate) this.props.options.onPipeUpdate(null);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
shouldComponentUpdate(props: CxProps, state: CxState): boolean {
|
|
238
|
+
if (props.deferredUntilIdle && state.deferToken != this.deferCounter) return false;
|
|
239
|
+
|
|
240
|
+
return (
|
|
241
|
+
state !== this.state ||
|
|
242
|
+
!props.params ||
|
|
243
|
+
!shallowEquals(props.params, this.props.params) ||
|
|
244
|
+
props.instance !== this.props.instance ||
|
|
245
|
+
props.widget !== this.props.widget ||
|
|
246
|
+
props.store !== this.props.store ||
|
|
247
|
+
props.parentInstance !== this.props.parentInstance ||
|
|
248
|
+
props.cultureInfo !== this.props.cultureInfo
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
componentDidCatchHandler(error: Error, info: any): void {
|
|
253
|
+
this.flags.preparing = false;
|
|
254
|
+
this.props.onError!(error, this.getInstance(), info);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
interface CxContextProps {
|
|
259
|
+
instance: Instance;
|
|
260
|
+
flags: { preparing?: boolean; dirty?: boolean; rendering?: boolean };
|
|
261
|
+
options?: any;
|
|
262
|
+
buster: number;
|
|
263
|
+
contentFactory?: (props: { children: any }) => any;
|
|
264
|
+
forceUpdate: () => void;
|
|
265
|
+
cultureInfo?: ResolvedCultureInfo;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
class CxContext extends VDOM.Component<CxContextProps, {}> {
|
|
269
|
+
renderCount: number;
|
|
270
|
+
timings: any;
|
|
271
|
+
content: any;
|
|
272
|
+
renderingContext?: RenderingContext;
|
|
273
|
+
|
|
274
|
+
constructor(props: CxContextProps) {
|
|
275
|
+
super(props);
|
|
276
|
+
this.renderCount = 0;
|
|
277
|
+
this.UNSAFE_componentWillReceiveProps(props);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
UNSAFE_componentWillReceiveProps(props: CxContextProps): void {
|
|
281
|
+
this.timings = {
|
|
282
|
+
start: now(),
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
let { instance, options, contentFactory } = props;
|
|
286
|
+
let count = 0,
|
|
287
|
+
visible,
|
|
288
|
+
context,
|
|
289
|
+
forceContinue;
|
|
290
|
+
|
|
291
|
+
//should not be tracked by parents for destroy
|
|
292
|
+
if (!(instance as any).detached)
|
|
293
|
+
throw new Error("The instance passed to a Cx component should be detached from its parent.");
|
|
294
|
+
|
|
295
|
+
if (this.props.instance !== instance && (this.props.instance as any).destroyTracked)
|
|
296
|
+
(this.props.instance as any).destroy();
|
|
297
|
+
|
|
298
|
+
this.props.flags.preparing = true;
|
|
299
|
+
|
|
300
|
+
if (this.props.cultureInfo) pushCulture(this.props.cultureInfo);
|
|
301
|
+
|
|
302
|
+
try {
|
|
303
|
+
do {
|
|
304
|
+
count++;
|
|
305
|
+
forceContinue = false;
|
|
306
|
+
context = new RenderingContext(options);
|
|
307
|
+
(context as any).forceUpdate = this.props.forceUpdate;
|
|
308
|
+
this.props.flags.dirty = false;
|
|
309
|
+
(instance as any).assignedRenderList = (context as any).getRootRenderList();
|
|
310
|
+
visible = (instance as any).scheduleExploreIfVisible(context);
|
|
311
|
+
if (visible) {
|
|
312
|
+
while (!(context as any).exploreStack.empty()) {
|
|
313
|
+
let inst = (context as any).exploreStack.pop();
|
|
314
|
+
//console.log("EXPLORE", inst.widget.constructor.name, inst.widget.tag, inst.widget.widgetId);
|
|
315
|
+
(inst as any).explore(context);
|
|
316
|
+
}
|
|
317
|
+
} else if ((instance as any).destroyTracked) {
|
|
318
|
+
(instance as any).destroy();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (this.props.flags.dirty && count <= 3 && Widget.optimizePrepare && now() - this.timings.start < 8) {
|
|
322
|
+
forceContinue = true;
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (visible) {
|
|
327
|
+
this.timings.afterExplore = now();
|
|
328
|
+
|
|
329
|
+
for (let i = 0; i < (context as any).prepareList.length; i++)
|
|
330
|
+
(context as any).prepareList[i].prepare(context);
|
|
331
|
+
this.timings.afterPrepare = now();
|
|
332
|
+
}
|
|
333
|
+
} while (
|
|
334
|
+
forceContinue ||
|
|
335
|
+
(this.props.flags.dirty && count <= 3 && Widget.optimizePrepare && now() - this.timings.start < 8)
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
if (visible) {
|
|
339
|
+
//walk in reverse order so children get rendered first
|
|
340
|
+
let renderList = (context as any).getRootRenderList();
|
|
341
|
+
while (renderList) {
|
|
342
|
+
for (let i = renderList.data.length - 1; i >= 0; i--) {
|
|
343
|
+
renderList.data[i].render(context);
|
|
344
|
+
}
|
|
345
|
+
renderList = renderList.right;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
this.content = getContent((instance as any).vdom);
|
|
349
|
+
if (contentFactory) this.content = contentFactory({ children: this.content });
|
|
350
|
+
this.timings.afterRender = now();
|
|
351
|
+
for (let i = 0; i < (context as any).cleanupList.length; i++)
|
|
352
|
+
(context as any).cleanupList[i].cleanup(context);
|
|
353
|
+
} else {
|
|
354
|
+
this.content = null;
|
|
355
|
+
this.timings.afterExplore = this.timings.afterPrepare = this.timings.afterRender = now();
|
|
356
|
+
}
|
|
357
|
+
} finally {
|
|
358
|
+
if (this.props.cultureInfo) popCulture(this.props.cultureInfo);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
this.timings.beforeVDOMRender = now();
|
|
362
|
+
this.props.flags.preparing = false;
|
|
363
|
+
this.props.flags.rendering = true;
|
|
364
|
+
this.renderingContext = context;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
render() {
|
|
368
|
+
return this.content;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
componentDidMount(): void {
|
|
372
|
+
this.componentDidUpdate();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
componentDidUpdate(): void {
|
|
376
|
+
this.props.flags.rendering = false;
|
|
377
|
+
this.timings.afterVDOMRender = now();
|
|
378
|
+
|
|
379
|
+
//let {instance} = this.props;
|
|
380
|
+
//instance.cleanup(this.renderingContext);
|
|
381
|
+
|
|
382
|
+
this.timings.afterCleanup = now();
|
|
383
|
+
this.renderCount++;
|
|
384
|
+
|
|
385
|
+
if (process.env.NODE_ENV !== "production") {
|
|
386
|
+
let { start, beforeVDOMRender, afterVDOMRender, afterPrepare, afterExplore, afterRender, afterCleanup } =
|
|
387
|
+
this.timings;
|
|
388
|
+
|
|
389
|
+
Timing.log(
|
|
390
|
+
vdomRenderFlag,
|
|
391
|
+
this.renderCount,
|
|
392
|
+
"cx",
|
|
393
|
+
(beforeVDOMRender - start + afterCleanup - afterVDOMRender).toFixed(2) + "ms",
|
|
394
|
+
"vdom",
|
|
395
|
+
(afterVDOMRender - beforeVDOMRender).toFixed(2) + "ms",
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
Timing.log(
|
|
399
|
+
appLoopFlag,
|
|
400
|
+
this.renderCount,
|
|
401
|
+
(this.renderingContext as any).options.name || "main",
|
|
402
|
+
"total",
|
|
403
|
+
(afterCleanup - start).toFixed(1) + "ms",
|
|
404
|
+
"explore",
|
|
405
|
+
(afterExplore - start).toFixed(1) + "ms",
|
|
406
|
+
"prepare",
|
|
407
|
+
(afterPrepare - afterExplore).toFixed(1),
|
|
408
|
+
"render",
|
|
409
|
+
(afterRender - afterPrepare).toFixed(1),
|
|
410
|
+
"vdom",
|
|
411
|
+
(afterVDOMRender - beforeVDOMRender).toFixed(1),
|
|
412
|
+
"cleanup",
|
|
413
|
+
(afterCleanup - afterVDOMRender).toFixed(1),
|
|
414
|
+
);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
componentWillUnmount(): void {
|
|
419
|
+
let { instance } = this.props;
|
|
420
|
+
if ((instance as any).destroyTracked) (instance as any).destroy();
|
|
421
|
+
}
|
|
422
|
+
}
|