@khanacademy/wonder-blocks-timing 2.0.3 → 2.1.1
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/CHANGELOG.md +18 -0
- package/dist/es/index.js +107 -230
- package/dist/index.js +260 -547
- package/dist/index.js.flow +1 -1
- package/package.json +3 -4
- package/src/__docs__/_overview_.stories.mdx +17 -0
- package/src/components/__docs__/migration.stories.mdx +112 -0
- package/{docs.md → src/components/__docs__/types.ischedule-actions.stories.mdx} +11 -260
- package/src/components/__docs__/with-action-scheduler-examples.js +80 -0
- package/src/components/__docs__/with-action-scheduler.stories.mdx +218 -0
- package/src/components/__tests__/action-scheduler-provider.test.js +7 -7
- package/src/components/__tests__/with-action-scheduler.test.js +6 -6
- package/src/components/action-scheduler-provider.js +2 -2
- package/src/components/with-action-scheduler.js +2 -2
- package/src/hooks/__docs__/use-interval.stories.mdx +80 -0
- package/src/hooks/__docs__/use-scheduled-interval.stories.mdx +147 -0
- package/src/hooks/{use-timeout.stories.mdx → __docs__/use-scheduled-timeout.stories.mdx} +13 -17
- package/src/hooks/__docs__/use-timeout.stories.mdx +80 -0
- package/src/hooks/__tests__/use-interval.test.js +124 -0
- package/src/hooks/__tests__/use-scheduled-interval.test.js +461 -0
- package/src/hooks/__tests__/use-scheduled-timeout.test.js +479 -0
- package/src/hooks/__tests__/use-timeout.test.js +94 -294
- package/src/hooks/internal/use-updating-ref.js +20 -0
- package/src/hooks/use-interval.js +37 -0
- package/src/hooks/use-scheduled-interval.js +73 -0
- package/src/hooks/use-scheduled-timeout.js +80 -0
- package/src/hooks/use-timeout.js +22 -55
- package/src/index.js +7 -4
- package/src/util/__tests__/action-scheduler.test.js +9 -9
- package/src/util/__tests__/animation-frame.test.js +2 -2
- package/src/util/__tests__/interval.test.js +2 -2
- package/src/util/__tests__/timeout.test.js +2 -2
- package/src/util/action-scheduler.js +4 -4
- package/src/util/animation-frame.js +2 -2
- package/src/util/interval.js +2 -2
- package/src/util/timeout.js +2 -2
- package/src/util/types.flowtest.js +2 -2
- package/LICENSE +0 -21
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +0 -353
- package/src/__tests__/generated-snapshot.test.js +0 -156
- package/src/components/with-action-scheduler.md +0 -18
package/dist/index.js.flow
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
export * from "../src/index
|
|
2
|
+
export * from "../src/index";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khanacademy/wonder-blocks-timing",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"design": "v1",
|
|
6
6
|
"publishConfig": {
|
|
7
7
|
"access": "public"
|
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
"react": "16.14.0"
|
|
18
18
|
},
|
|
19
19
|
"devDependencies": {
|
|
20
|
-
"wb-dev-build-settings": "^0.
|
|
20
|
+
"wb-dev-build-settings": "^0.7.1"
|
|
21
21
|
},
|
|
22
22
|
"author": "",
|
|
23
|
-
"license": "MIT"
|
|
24
|
-
"gitHead": "9ebea88533e702011165072f090a377e02fa3f0f"
|
|
23
|
+
"license": "MIT"
|
|
25
24
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
2
|
+
|
|
3
|
+
<Meta
|
|
4
|
+
title="Timing / Overview"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
# Timing
|
|
13
|
+
|
|
14
|
+
`wonder-blocks-timing` provides abstractions for common timing APIs like
|
|
15
|
+
`setTimeout`, `setInterval` and `requestAnimationFrame` that are aware of React
|
|
16
|
+
component lifecycles, ensuring that scheduled timer actions are not unexpectedly
|
|
17
|
+
dangling after a component unmounts.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
2
|
+
|
|
3
|
+
<Meta
|
|
4
|
+
title="Timing / withActionScheduler / Migration from standard API"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
11
|
+
|
|
12
|
+
# withActionSceduler
|
|
13
|
+
|
|
14
|
+
## Migration from standard API
|
|
15
|
+
|
|
16
|
+
Migrating from the standard API can be done by:
|
|
17
|
+
|
|
18
|
+
1. Wrapping your component with the `withActionScheduler` HOC (and, if using Flow, using the `WithActionSchedulerProps` type to extend your components props by spreading the type into
|
|
19
|
+
your component's `Props` type)
|
|
20
|
+
2. Using the new `schedule` prop in your component instead of `setTimeout`, `setInterval` and `requestAnimationFrame`
|
|
21
|
+
|
|
22
|
+
### Migration Example
|
|
23
|
+
|
|
24
|
+
Let's imagine we have a component that uses `setTimeout` like this:
|
|
25
|
+
|
|
26
|
+
```js static
|
|
27
|
+
type Props = {||};
|
|
28
|
+
|
|
29
|
+
type State = {
|
|
30
|
+
timerFired: boolean,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class MyLegacyComponent extends React.Component<Props, State> {
|
|
34
|
+
_timeoutID: TimeoutID;
|
|
35
|
+
|
|
36
|
+
state: State = {
|
|
37
|
+
timerFired: false;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
componentDidMount() {
|
|
41
|
+
this.timeoutID = setTimeout(
|
|
42
|
+
() => this.setState({timerFired: true}),
|
|
43
|
+
2000,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
componentWillUnmount() {
|
|
48
|
+
/* 0 is a valid ID for a timeout */
|
|
49
|
+
if (this.timeoutID != null) {
|
|
50
|
+
clearTimeout(this.timeoutID);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
renderState() {
|
|
55
|
+
const {timerFired} = this.state;
|
|
56
|
+
if (timerFired) {
|
|
57
|
+
return "...fired!";
|
|
58
|
+
}
|
|
59
|
+
return "pending...";
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
render() {
|
|
63
|
+
return <View>Legacy Component {this.renderState()}</View>;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
We can rewrite it to use the Wonder Blocks Timing API like this:
|
|
69
|
+
|
|
70
|
+
```js static
|
|
71
|
+
type Props = {|
|
|
72
|
+
/**
|
|
73
|
+
* These props will be injected into your component. They won't appear
|
|
74
|
+
* as part of the public props of the component since `withActionSceduler`
|
|
75
|
+
* will excluding them from the props of the component it returns.
|
|
76
|
+
*/
|
|
77
|
+
...withActionSchedulerProps
|
|
78
|
+
|};
|
|
79
|
+
|
|
80
|
+
type State = {
|
|
81
|
+
timerFired: boolean,
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class MyWonderBlocksComponentImpl extends React.Component<Props, State> {
|
|
85
|
+
state: State = {
|
|
86
|
+
timerFired: false;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
componentDidMount() {
|
|
90
|
+
const {schedule} = this.props;
|
|
91
|
+
schedule.timeout(() => this.setState({timerFired: true}), 2000);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
renderState() {
|
|
95
|
+
const {timerFired} = this.state;
|
|
96
|
+
if (timerFired) {
|
|
97
|
+
return "...fired!";
|
|
98
|
+
}
|
|
99
|
+
return "pending...";
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
render() {
|
|
103
|
+
return <View>Wonder Blocks Component {this.renderState()}</View>;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* The component that you would export as a drop-in replacement for your
|
|
109
|
+
* legacy component.
|
|
110
|
+
*/
|
|
111
|
+
const MyWonderBlocksComponent = withActionScheduler(MyWonderBlocksComponentImpl);
|
|
112
|
+
```
|
|
@@ -1,164 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
`requestAnimationFrame` that are aware of React component lifecycles, ensuring
|
|
3
|
-
that scheduled timer actions are not unexpectedly dangling after a component
|
|
4
|
-
unmounts.
|
|
5
|
-
|
|
6
|
-
Access to the timing API is provided via the `withActionScheduler` higher order
|
|
7
|
-
component.
|
|
8
|
-
|
|
9
|
-
### Timing API Usage Example
|
|
10
|
-
|
|
11
|
-
The following component, `MyNaughtyComponent`, will keep spamming our pretend
|
|
12
|
-
log even after it was unmounted.
|
|
13
|
-
|
|
14
|
-
```jsx
|
|
15
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
16
|
-
import {IDProvider, View} from "@khanacademy/wonder-blocks-core";
|
|
17
|
-
|
|
18
|
-
class Unmounter extends React.Component {
|
|
19
|
-
constructor() {
|
|
20
|
-
super();
|
|
21
|
-
this.state = {
|
|
22
|
-
mountKids: true,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
maybeRenderKids() {
|
|
27
|
-
if (this.state.mountKids) {
|
|
28
|
-
return (
|
|
29
|
-
<React.Fragment>
|
|
30
|
-
<Button onClick={() => this.onClick()}>Unmount</Button>
|
|
31
|
-
{this.props.children}
|
|
32
|
-
</React.Fragment>
|
|
33
|
-
);
|
|
34
|
-
} else {
|
|
35
|
-
return "Children unmounted";
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
onClick() {
|
|
40
|
-
this.setState({mountKids: false});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
render() {
|
|
44
|
-
return (
|
|
45
|
-
<View>
|
|
46
|
-
{this.maybeRenderKids()}
|
|
47
|
-
</View>
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
class MyNaughtyComponent extends React.Component {
|
|
53
|
-
componentDidMount() {
|
|
54
|
-
const {targetId} = this.props;
|
|
55
|
-
let counter = 0;
|
|
56
|
-
const domElement = document.getElementById(targetId);
|
|
57
|
-
setInterval(() => {
|
|
58
|
-
domElement.innerText = "Naughty interval logged: " + counter++;
|
|
59
|
-
}, 200);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
render() {
|
|
63
|
-
return <View>NaughtyComponent here</View>;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<IDProvider>
|
|
69
|
-
{id => (
|
|
70
|
-
<View>
|
|
71
|
-
<Unmounter>
|
|
72
|
-
<MyNaughtyComponent targetId={id} />
|
|
73
|
-
</Unmounter>
|
|
74
|
-
<View>
|
|
75
|
-
<View id={id}></View>
|
|
76
|
-
</View>
|
|
77
|
-
</View>
|
|
78
|
-
)}
|
|
79
|
-
</IDProvider>
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
But if we use `withActionScheduler` and the `interval` method, everything is
|
|
83
|
-
fine. Unmount the component, and the logging stops.
|
|
84
|
-
|
|
85
|
-
```jsx
|
|
86
|
-
import {withActionScheduler} from "@khanacademy/wonder-blocks-timing";
|
|
87
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
88
|
-
import {IDProvider, View} from "@khanacademy/wonder-blocks-core";
|
|
89
|
-
|
|
90
|
-
class Unmounter extends React.Component {
|
|
91
|
-
constructor() {
|
|
92
|
-
super();
|
|
93
|
-
this.state = {
|
|
94
|
-
mountKids: true,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
maybeRenderKids() {
|
|
99
|
-
if (this.state.mountKids) {
|
|
100
|
-
return (
|
|
101
|
-
<React.Fragment>
|
|
102
|
-
<Button onClick={() => this.onClick()}>Unmount</Button>
|
|
103
|
-
{this.props.children}
|
|
104
|
-
</React.Fragment>
|
|
105
|
-
);
|
|
106
|
-
} else {
|
|
107
|
-
return "Children unmounted";
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
onClick() {
|
|
112
|
-
this.setState({mountKids: false});
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
render() {
|
|
116
|
-
return (
|
|
117
|
-
<View>
|
|
118
|
-
{this.maybeRenderKids()}
|
|
119
|
-
</View>
|
|
120
|
-
);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
1
|
+
import {Meta} from "@storybook/addon-docs";
|
|
123
2
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
render() {
|
|
135
|
-
return <View>GoodComponent here</View>;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const MyGoodComponentWithScheduler = withActionScheduler(MyGoodComponent);
|
|
140
|
-
|
|
141
|
-
<IDProvider>
|
|
142
|
-
{id => (
|
|
143
|
-
<View>
|
|
144
|
-
<Unmounter>
|
|
145
|
-
<MyGoodComponentWithScheduler targetId={id} />
|
|
146
|
-
</Unmounter>
|
|
147
|
-
<View>
|
|
148
|
-
<View id={id}></View>
|
|
149
|
-
</View>
|
|
150
|
-
</View>
|
|
151
|
-
)}
|
|
152
|
-
</IDProvider>
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
<!-- Styleguidist doesn't support the extended syntax for custom header IDs.
|
|
156
|
-
If that ever changes, this should be:
|
|
157
|
-
`### API Overiview {#timing-api-overview}`
|
|
158
|
-
-->
|
|
159
|
-
<h3 id="timing-api-overview">API Overview</h3>
|
|
3
|
+
<Meta
|
|
4
|
+
title="Timing / withActionScheduler / Types / IScheduleActions"
|
|
5
|
+
parameters={{
|
|
6
|
+
chromatic: {
|
|
7
|
+
disableSnapshot: true,
|
|
8
|
+
},
|
|
9
|
+
}}
|
|
10
|
+
/>
|
|
160
11
|
|
|
161
|
-
|
|
12
|
+
# IScheduleActions
|
|
162
13
|
|
|
163
14
|
The `IScheduleActions` interface provides 4 (four) different functions:
|
|
164
15
|
|
|
@@ -303,104 +154,4 @@ The `IAnimationFrame` interface provides additional calls to manipulate an anima
|
|
|
303
154
|
| --- | --- | --- |
|
|
304
155
|
| `isSet` | `boolean` | A read-only property for determining if the request is set (aka pending). Returns `true` if the animation frame is set, otherwise `false`. |
|
|
305
156
|
| `set` | `()` `=>` `void` | If the request is pending, this cancels that pending request and starts a request afresh. If the request is not pending, this starts the request. Can be used to re-request an already invokd or cleared request. |
|
|
306
|
-
| `clear` | `(clearPolicy?:` `ClearPolicy)` `=>` `void` | If the request is pending, this cancels that pending request. If no request is pending, this does nothing. When the optional `clearPolicy` argument is `ClearPolicy.Resolve`, and the request was in the set state when called, the associated action is invoked after cancelling the requst. The `clearPolicy` parameter defaults to `ClearPolicy.Cancel`. This call does nothing if there was no pending request (i.e. when `isSet` is `false`). |
|
|
307
|
-
|
|
308
|
-
### Migration from standard API
|
|
309
|
-
|
|
310
|
-
Migrating from the standard API can be done by:
|
|
311
|
-
|
|
312
|
-
1. Wrapping your component with the `withActionScheduler` HOC (and, if using Flow, using the `WithActionSchedulerProps` type to extend your components props by spreading the type into
|
|
313
|
-
your component's `Props` type)
|
|
314
|
-
2. Using the new `schedule` prop in your component instead of `setTimeout`, `setInterval` and `requestAnimationFrame`
|
|
315
|
-
|
|
316
|
-
#### Migration Example
|
|
317
|
-
|
|
318
|
-
Let's imagine we have a component that uses `setTimeout` like this:
|
|
319
|
-
|
|
320
|
-
```js static
|
|
321
|
-
type Props = {||};
|
|
322
|
-
|
|
323
|
-
type State = {
|
|
324
|
-
timerFired: boolean,
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
class MyLegacyComponent extends React.Component<Props, State> {
|
|
328
|
-
_timeoutID: TimeoutID;
|
|
329
|
-
|
|
330
|
-
state: State = {
|
|
331
|
-
timerFired: false;
|
|
332
|
-
};
|
|
333
|
-
|
|
334
|
-
componentDidMount() {
|
|
335
|
-
this.timeoutID = setTimeout(
|
|
336
|
-
() => this.setState({timerFired: true}),
|
|
337
|
-
2000,
|
|
338
|
-
);
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
componentWillUnmount() {
|
|
342
|
-
/* 0 is a valid ID for a timeout */
|
|
343
|
-
if (this.timeoutID != null) {
|
|
344
|
-
clearTimeout(this.timeoutID);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
renderState() {
|
|
349
|
-
const {timerFired} = this.state;
|
|
350
|
-
if (timerFired) {
|
|
351
|
-
return "...fired!";
|
|
352
|
-
}
|
|
353
|
-
return "pending...";
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
render() {
|
|
357
|
-
return <View>Legacy Component {this.renderState()}</View>;
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
We can rewrite it to use the Wonder Blocks Timing API like this:
|
|
363
|
-
|
|
364
|
-
```js static
|
|
365
|
-
type Props = {|
|
|
366
|
-
/**
|
|
367
|
-
* These props will be injected into your component. They won't appear
|
|
368
|
-
* as part of the public props of the component since `withActionSceduler`
|
|
369
|
-
* will excluding them from the props of the component it returns.
|
|
370
|
-
*/
|
|
371
|
-
...withActionSchedulerProps
|
|
372
|
-
|};
|
|
373
|
-
|
|
374
|
-
type State = {
|
|
375
|
-
timerFired: boolean,
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
class MyWonderBlocksComponentImpl extends React.Component<Props, State> {
|
|
379
|
-
state: State = {
|
|
380
|
-
timerFired: false;
|
|
381
|
-
};
|
|
382
|
-
|
|
383
|
-
componentDidMount() {
|
|
384
|
-
const {schedule} = this.props;
|
|
385
|
-
schedule.timeout(() => this.setState({timerFired: true}), 2000);
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
renderState() {
|
|
389
|
-
const {timerFired} = this.state;
|
|
390
|
-
if (timerFired) {
|
|
391
|
-
return "...fired!";
|
|
392
|
-
}
|
|
393
|
-
return "pending...";
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
render() {
|
|
397
|
-
return <View>Wonder Blocks Component {this.renderState()}</View>;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
/**
|
|
402
|
-
* The component that you would export as a drop-in replacement for your
|
|
403
|
-
* legacy component.
|
|
404
|
-
*/
|
|
405
|
-
const MyWonderBlocksComponent = withActionScheduler(MyWonderBlocksComponentImpl);
|
|
406
|
-
```
|
|
157
|
+
| `clear` | `(clearPolicy?:` `ClearPolicy)` `=>` `void` | If the request is pending, this cancels that pending request. If no request is pending, this does nothing. When the optional `clearPolicy` argument is `ClearPolicy.Resolve`, and the request was in the set state when called, the associated action is invoked after cancelling the requst. The `clearPolicy` parameter defaults to `ClearPolicy.Cancel`. This call does nothing if there was no pending request (i.e. when `isSet` is `false`). |
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import Button from "@khanacademy/wonder-blocks-button";
|
|
4
|
+
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
+
import {withActionScheduler} from "@khanacademy/wonder-blocks-timing";
|
|
6
|
+
import type {
|
|
7
|
+
WithActionSchedulerProps,
|
|
8
|
+
WithoutActionScheduler,
|
|
9
|
+
} from "@khanacademy/wonder-blocks-timing";
|
|
10
|
+
|
|
11
|
+
export function Unmounter(props: {|children: React.Node|}): React.Node {
|
|
12
|
+
const [mountKids, setMountKids] = React.useState(true);
|
|
13
|
+
|
|
14
|
+
const maybeRenderKids = () => {
|
|
15
|
+
if (!mountKids) {
|
|
16
|
+
return "Children unmounted";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return (
|
|
20
|
+
<>
|
|
21
|
+
<Button
|
|
22
|
+
onClick={() => {
|
|
23
|
+
setMountKids(false);
|
|
24
|
+
}}
|
|
25
|
+
>
|
|
26
|
+
Unmount
|
|
27
|
+
</Button>
|
|
28
|
+
{props.children}
|
|
29
|
+
</>
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
return <View>{maybeRenderKids()}</View>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export class MyNaughtyComponent extends React.Component<{|targetId: string|}> {
|
|
37
|
+
componentDidMount() {
|
|
38
|
+
const {targetId} = this.props;
|
|
39
|
+
let counter = 0;
|
|
40
|
+
const domElement: HTMLElement = (document.getElementById(
|
|
41
|
+
targetId,
|
|
42
|
+
): any);
|
|
43
|
+
|
|
44
|
+
setInterval(() => {
|
|
45
|
+
domElement.innerText = "Naughty interval logged: " + counter++;
|
|
46
|
+
}, 200);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
render(): React.Node {
|
|
50
|
+
return <View>NaughtyComponent here</View>;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
type Props = {|
|
|
55
|
+
...WithActionSchedulerProps,
|
|
56
|
+
targetId: string,
|
|
57
|
+
|};
|
|
58
|
+
|
|
59
|
+
export class MyGoodComponent extends React.Component<Props> {
|
|
60
|
+
componentDidMount() {
|
|
61
|
+
const {targetId, schedule} = this.props;
|
|
62
|
+
let counter = 0;
|
|
63
|
+
const domElement: HTMLElement = (document.getElementById(
|
|
64
|
+
targetId,
|
|
65
|
+
): any);
|
|
66
|
+
|
|
67
|
+
schedule.interval(() => {
|
|
68
|
+
domElement.innerText = "Naughty interval logged: " + counter++;
|
|
69
|
+
}, 200);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
render(): React.Node {
|
|
73
|
+
return <View>GoodComponent here</View>;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const MyGoodComponentWithScheduler: React.AbstractComponent<
|
|
78
|
+
WithoutActionScheduler<React.ElementConfig<typeof MyGoodComponent>>,
|
|
79
|
+
MyGoodComponent,
|
|
80
|
+
> = withActionScheduler(MyGoodComponent);
|