@khanacademy/wonder-blocks-timing 2.1.1 → 2.1.2
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 +13 -0
- package/dist/components/action-scheduler-provider.d.ts +26 -0
- package/dist/components/action-scheduler-provider.js.flow +35 -0
- package/dist/components/with-action-scheduler.d.ts +14 -0
- package/dist/components/with-action-scheduler.js.flow +26 -0
- package/dist/es/index.js +157 -119
- package/dist/hooks/internal/use-updating-ref.d.ts +13 -0
- package/dist/hooks/internal/use-updating-ref.js.flow +22 -0
- package/dist/hooks/use-interval.d.ts +8 -0
- package/dist/hooks/use-interval.js.flow +18 -0
- package/dist/hooks/use-scheduled-interval.d.ts +2 -0
- package/dist/hooks/use-scheduled-interval.js.flow +13 -0
- package/dist/hooks/use-scheduled-timeout.d.ts +2 -0
- package/dist/hooks/use-scheduled-timeout.js.flow +13 -0
- package/dist/hooks/use-timeout.d.ts +8 -0
- package/dist/hooks/use-timeout.js.flow +18 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +158 -123
- package/dist/index.js.flow +31 -2
- package/dist/util/action-scheduler.d.ts +21 -0
- package/dist/util/action-scheduler.js.flow +39 -0
- package/dist/util/animation-frame.d.ts +62 -0
- package/dist/util/animation-frame.js.flow +71 -0
- package/dist/util/interval.d.ts +60 -0
- package/dist/util/interval.js.flow +70 -0
- package/dist/util/policies.d.ts +8 -0
- package/dist/util/policies.js.flow +17 -0
- package/dist/util/timeout.d.ts +62 -0
- package/dist/util/timeout.js.flow +72 -0
- package/dist/util/types.d.ts +228 -0
- package/dist/util/types.js.flow +235 -0
- package/dist/util/types.typestest.d.ts +1 -0
- package/dist/util/types.typestest.js.flow +6 -0
- package/package.json +3 -3
- package/src/components/__tests__/{action-scheduler-provider.test.js → action-scheduler-provider.test.tsx} +0 -2
- package/src/components/__tests__/{with-action-scheduler.test.js → with-action-scheduler.test.tsx} +6 -6
- package/src/components/{action-scheduler-provider.js → action-scheduler-provider.ts} +4 -5
- package/src/components/{with-action-scheduler.js → with-action-scheduler.tsx} +10 -18
- package/src/hooks/__tests__/{use-interval.test.js → use-interval.test.ts} +5 -6
- package/src/hooks/__tests__/{use-scheduled-interval.test.js → use-scheduled-interval.test.ts} +5 -6
- package/src/hooks/__tests__/{use-scheduled-timeout.test.js → use-scheduled-timeout.test.ts} +9 -10
- package/src/hooks/__tests__/{use-timeout.test.js → use-timeout.test.ts} +5 -6
- package/src/hooks/internal/{use-updating-ref.js → use-updating-ref.ts} +5 -2
- package/src/hooks/{use-interval.js → use-interval.ts} +1 -2
- package/src/hooks/{use-scheduled-interval.js → use-scheduled-interval.ts} +2 -2
- package/src/hooks/{use-scheduled-timeout.js → use-scheduled-timeout.ts} +2 -2
- package/src/hooks/{use-timeout.js → use-timeout.ts} +1 -2
- package/src/{index.js → index.ts} +0 -1
- package/src/util/__tests__/{action-scheduler.test.js → action-scheduler.test.ts} +6 -16
- package/src/util/__tests__/{animation-frame.test.js → animation-frame.test.ts} +8 -7
- package/src/util/__tests__/{interval.test.js → interval.test.ts} +1 -2
- package/src/util/__tests__/{timeout.test.js → timeout.test.ts} +1 -2
- package/src/util/{action-scheduler.js → action-scheduler.ts} +13 -6
- package/src/util/{animation-frame.js → animation-frame.ts} +4 -4
- package/src/util/{interval.js → interval.ts} +5 -4
- package/src/util/{policies.js → policies.ts} +2 -3
- package/src/util/{timeout.js → timeout.ts} +5 -4
- package/src/util/{types.js → types.ts} +21 -28
- package/src/util/{types.flowtest.js → types.typestest.tsx} +20 -18
- package/tsconfig.json +11 -0
- package/tsconfig.tsbuildinfo +1 -0
- package/src/components/__docs__/migration.stories.mdx +0 -112
- package/src/components/__docs__/types.ischedule-actions.stories.mdx +0 -157
- package/src/components/__docs__/with-action-scheduler-examples.js +0 -80
- package/src/components/__docs__/with-action-scheduler.stories.mdx +0 -218
- package/src/hooks/__docs__/use-interval.stories.mdx +0 -80
- package/src/hooks/__docs__/use-scheduled-interval.stories.mdx +0 -147
- package/src/hooks/__docs__/use-scheduled-timeout.stories.mdx +0 -148
- package/src/hooks/__docs__/use-timeout.stories.mdx +0 -80
|
@@ -1,218 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Subtitle, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
import {IDProvider, View} from "@khanacademy/wonder-blocks-core";
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
Unmounter,
|
|
6
|
-
MyGoodComponentWithScheduler,
|
|
7
|
-
MyNaughtyComponent,
|
|
8
|
-
} from "./with-action-scheduler-examples.js";
|
|
9
|
-
import ComponentInfo from "../../../../../.storybook/components/component-info.js";
|
|
10
|
-
import {name, version} from "../../../package.json";
|
|
11
|
-
|
|
12
|
-
<Meta
|
|
13
|
-
title="Timing / withActionScheduler"
|
|
14
|
-
parameters={{
|
|
15
|
-
previewTabs: {
|
|
16
|
-
canvas: {hidden: true},
|
|
17
|
-
},
|
|
18
|
-
viewMode: "docs",
|
|
19
|
-
chromatic: {
|
|
20
|
-
disableSnapshot: true,
|
|
21
|
-
},
|
|
22
|
-
}}
|
|
23
|
-
decorators={[
|
|
24
|
-
(Story) => (
|
|
25
|
-
<View>{Story()}</View>
|
|
26
|
-
),
|
|
27
|
-
]}
|
|
28
|
-
/>
|
|
29
|
-
|
|
30
|
-
# withActionSceduler
|
|
31
|
-
|
|
32
|
-
<Subtitle>
|
|
33
|
-
<ComponentInfo name={name} version={version} />
|
|
34
|
-
</Subtitle>
|
|
35
|
-
|
|
36
|
-
This is a higher order component (HOC) that attaches the given component to an
|
|
37
|
-
[`IScheduleActions`](#ischeduleactions) instance. Any actions scheduled will automatically be
|
|
38
|
-
cleared on unmount. This allows for "set it and forget it" behavior that won't
|
|
39
|
-
leave timers dangling when the component's lifecycle ends.
|
|
40
|
-
|
|
41
|
-
For more details on using this component and the [`IScheduleActions`](#ischeduleactions) interface,
|
|
42
|
-
see the [API overview](#timing-api-overview).
|
|
43
|
-
|
|
44
|
-
## Flow Types
|
|
45
|
-
If you are using Flow typing, you can use the `WithActionSchedulerProps` type
|
|
46
|
-
to build the props for the component that you will pass to the `withActionScheduler`
|
|
47
|
-
function by spreading the type into your component's `Props` type.
|
|
48
|
-
|
|
49
|
-
The added `schedule` prop is of type [`IScheduleActions`](#ischeduleactions). This is what the
|
|
50
|
-
`withActionScheduler` function injects to your component.
|
|
51
|
-
|
|
52
|
-
The returned value from `withActionScheduler` is a React component with props of
|
|
53
|
-
type `TProps`.
|
|
54
|
-
|
|
55
|
-
Access to the [timing API](/docs/timing-types-ischeduleactions--page) is provided via the `withActionScheduler` higher order
|
|
56
|
-
component.
|
|
57
|
-
|
|
58
|
-
## Usage
|
|
59
|
-
|
|
60
|
-
### Incorrect Usage
|
|
61
|
-
|
|
62
|
-
The following component, `MyNaughtyComponent`, will keep spamming our pretend
|
|
63
|
-
log even after it was unmounted.
|
|
64
|
-
|
|
65
|
-
export const IncorrectUsage = () => (
|
|
66
|
-
<IDProvider id="incorrect">
|
|
67
|
-
{(id) => (
|
|
68
|
-
<View>
|
|
69
|
-
<Unmounter>
|
|
70
|
-
<MyNaughtyComponent targetId={id} />
|
|
71
|
-
</Unmounter>
|
|
72
|
-
<View id={id} />
|
|
73
|
-
</View>
|
|
74
|
-
)}
|
|
75
|
-
</IDProvider>
|
|
76
|
-
);
|
|
77
|
-
|
|
78
|
-
<Canvas>
|
|
79
|
-
<Story name="IncorrectUsage">
|
|
80
|
-
<IncorrectUsage />
|
|
81
|
-
</Story>
|
|
82
|
-
</Canvas>
|
|
83
|
-
|
|
84
|
-
```jsx
|
|
85
|
-
function Unmounter(props: {|children: React.Node|}): React.Node {
|
|
86
|
-
const [mountKids, setMountKids] = React.useState(true);
|
|
87
|
-
|
|
88
|
-
const maybeRenderKids = () => {
|
|
89
|
-
if (!mountKids) {
|
|
90
|
-
return "Children unmounted";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return (
|
|
94
|
-
<>
|
|
95
|
-
<Button
|
|
96
|
-
onClick={() => {
|
|
97
|
-
setMountKids(false);
|
|
98
|
-
}}
|
|
99
|
-
>
|
|
100
|
-
Unmount
|
|
101
|
-
</Button>
|
|
102
|
-
{props.children}
|
|
103
|
-
</>
|
|
104
|
-
);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
return <View>{maybeRenderKids()}</View>;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
class MyNaughtyComponent extends React.Component<{|targetId: string|}> {
|
|
111
|
-
componentDidMount() {
|
|
112
|
-
const {targetId} = this.props;
|
|
113
|
-
let counter = 0;
|
|
114
|
-
const domElement: HTMLElement = (document.getElementById(
|
|
115
|
-
targetId,
|
|
116
|
-
): any);
|
|
117
|
-
|
|
118
|
-
setInterval(() => {
|
|
119
|
-
domElement.innerText = "Naughty interval logged: " + counter++;
|
|
120
|
-
}, 200);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
render(): React.Node {
|
|
124
|
-
return <View>NaughtyComponent here</View>;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const IncorrectUsage = () => (
|
|
129
|
-
<IDProvider id="incorrect">
|
|
130
|
-
{(id) => (
|
|
131
|
-
<View>
|
|
132
|
-
<Unmounter>
|
|
133
|
-
<MyNaughtyComponent targetId={id} />
|
|
134
|
-
</Unmounter>
|
|
135
|
-
<View id={id} />
|
|
136
|
-
</View>
|
|
137
|
-
)}
|
|
138
|
-
</IDProvider>
|
|
139
|
-
);
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Correct Usage
|
|
143
|
-
|
|
144
|
-
But if we use `withActionScheduler` and the `interval` method, everything is
|
|
145
|
-
fine. Unmount the component, and the logging stops.
|
|
146
|
-
|
|
147
|
-
export const CorrectUsage = () => (
|
|
148
|
-
<IDProvider id="correct">
|
|
149
|
-
{(id) => (
|
|
150
|
-
<View>
|
|
151
|
-
<Unmounter>
|
|
152
|
-
<MyGoodComponentWithScheduler targetId={id} />
|
|
153
|
-
</Unmounter>
|
|
154
|
-
<View id={id} />
|
|
155
|
-
</View>
|
|
156
|
-
)}
|
|
157
|
-
</IDProvider>
|
|
158
|
-
);
|
|
159
|
-
|
|
160
|
-
<Canvas>
|
|
161
|
-
<Story name="CorrectUsage">
|
|
162
|
-
<CorrectUsage />
|
|
163
|
-
</Story>
|
|
164
|
-
</Canvas>
|
|
165
|
-
|
|
166
|
-
```jsx
|
|
167
|
-
import {withActionScheduler} from "@khanacademy/wonder-blocks-timing";
|
|
168
|
-
import type {
|
|
169
|
-
WithActionSchedulerProps,
|
|
170
|
-
WithoutActionScheduler,
|
|
171
|
-
} from "@khanacademy/wonder-blocks-timing";
|
|
172
|
-
|
|
173
|
-
type Props = {|
|
|
174
|
-
...WithActionSchedulerProps,
|
|
175
|
-
targetId: string,
|
|
176
|
-
|};
|
|
177
|
-
|
|
178
|
-
class MyGoodComponent extends React.Component<Props> {
|
|
179
|
-
componentDidMount() {
|
|
180
|
-
const {targetId, schedule} = this.props;
|
|
181
|
-
let counter = 0;
|
|
182
|
-
const domElement: HTMLElement = (document.getElementById(
|
|
183
|
-
targetId,
|
|
184
|
-
): any);
|
|
185
|
-
|
|
186
|
-
schedule.interval(() => {
|
|
187
|
-
domElement.innerText = "Naughty interval logged: " + counter++;
|
|
188
|
-
}, 200);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
render(): React.Node {
|
|
192
|
-
return <View>GoodComponent here</View>;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
const MyGoodComponentWithScheduler: React.AbstractComponent<
|
|
197
|
-
WithoutActionScheduler<React.ElementConfig<typeof MyGoodComponent>>,
|
|
198
|
-
MyGoodComponent,
|
|
199
|
-
> = withActionScheduler(MyGoodComponent);
|
|
200
|
-
|
|
201
|
-
// This is the same as the previous example
|
|
202
|
-
function Unmounter(props: {|children: React.Node|}): React.Node {
|
|
203
|
-
...
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const CorrectUsage = () => (
|
|
207
|
-
<IDProvider id="correct">
|
|
208
|
-
{(id) => (
|
|
209
|
-
<View>
|
|
210
|
-
<Unmounter>
|
|
211
|
-
<MyGoodComponentWithScheduler targetId={id} />
|
|
212
|
-
</Unmounter>
|
|
213
|
-
<View id={id} />
|
|
214
|
-
</View>
|
|
215
|
-
)}
|
|
216
|
-
</IDProvider>
|
|
217
|
-
);
|
|
218
|
-
```
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {useInterval} from "@khanacademy/wonder-blocks-timing";
|
|
8
|
-
|
|
9
|
-
<Meta
|
|
10
|
-
title="Timing/useInterval"
|
|
11
|
-
parameters={{
|
|
12
|
-
chromatic: {
|
|
13
|
-
disableSnapshot: true,
|
|
14
|
-
},
|
|
15
|
-
}}
|
|
16
|
-
/>
|
|
17
|
-
|
|
18
|
-
# `useInterval`
|
|
19
|
-
|
|
20
|
-
`useInterval` is a hook that provides a simple API for using intervals safely.
|
|
21
|
-
It is defined as follows:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
function useInterval(
|
|
25
|
-
action: () => mixed,
|
|
26
|
-
intervalMs: number,
|
|
27
|
-
active: boolean,
|
|
28
|
-
): void;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Notes:
|
|
32
|
-
|
|
33
|
-
- Setting `active` to `true` will start the interval and setting it to `false`
|
|
34
|
-
will stop it
|
|
35
|
-
- Changing the value of `timeoutMs` will reset the interval, changing `action`
|
|
36
|
-
will not.
|
|
37
|
-
|
|
38
|
-
export const BasicUsage = () => {
|
|
39
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
40
|
-
const [active, setActive] = React.useState(false);
|
|
41
|
-
const callback = React.useCallback(() => {
|
|
42
|
-
setCallCount((callCount) => callCount + 1);
|
|
43
|
-
}, []);
|
|
44
|
-
useInterval(callback, 1000, active);
|
|
45
|
-
return (
|
|
46
|
-
<View>
|
|
47
|
-
<View>callCount = {callCount}</View>
|
|
48
|
-
<View>active = {active.toString()}</View>
|
|
49
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
50
|
-
Toggle active
|
|
51
|
-
</Button>
|
|
52
|
-
</View>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
<Canvas>
|
|
57
|
-
<Story name="BasicUsage">
|
|
58
|
-
<BasicUsage />
|
|
59
|
-
</Story>
|
|
60
|
-
</Canvas>
|
|
61
|
-
|
|
62
|
-
```jsx
|
|
63
|
-
export const BasicUsage = () => {
|
|
64
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
65
|
-
const [active, setActive] = React.useState(false);
|
|
66
|
-
const callback = React.useCallback(() => {
|
|
67
|
-
setCallCount((callCount) => callCount + 1);
|
|
68
|
-
}, []);
|
|
69
|
-
useInterval(callback, 1000, active);
|
|
70
|
-
return (
|
|
71
|
-
<View>
|
|
72
|
-
<View>callCount = {callCount}</View>
|
|
73
|
-
<View>active = {active.toString()}</View>
|
|
74
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
75
|
-
Toggle active
|
|
76
|
-
</Button>
|
|
77
|
-
</View>
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
```
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {ClearPolicy, SchedulePolicy} from "../../util/policies.js";
|
|
8
|
-
import {useScheduledInterval} from "@khanacademy/wonder-blocks-timing";
|
|
9
|
-
|
|
10
|
-
<Meta
|
|
11
|
-
title="Timing/useScheduledInterval"
|
|
12
|
-
parameters={{
|
|
13
|
-
chromatic: {
|
|
14
|
-
disableSnapshot: true,
|
|
15
|
-
},
|
|
16
|
-
}}
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
|
-
# `useScheduledInterval`
|
|
20
|
-
|
|
21
|
-
`useScheduledInterval` is a hook that provides a convenient API for setting and clearing
|
|
22
|
-
an interval. It is defined as follows:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
function useScheduledInterval(
|
|
26
|
-
action: () => mixed,
|
|
27
|
-
timeoutMs: number,
|
|
28
|
-
options?: {|
|
|
29
|
-
schedulePolicy?: "schedule-immediately" | "schedule-on-demand",
|
|
30
|
-
clearPolicy?: "resolve-on-clear" | "cancel-on-clear",
|
|
31
|
-
|},
|
|
32
|
-
): ITimeout;
|
|
33
|
-
|
|
34
|
-
interface ITimeout {
|
|
35
|
-
get isSet(): boolean;
|
|
36
|
-
set(): void;
|
|
37
|
-
clear(policy?: ClearPolicy): void;
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
By default the interval will be set immediately up creation. The `options` parameter can
|
|
42
|
-
be used to control when when the interval is schedule and whether or not `action` should be
|
|
43
|
-
called when the interval is cleared.
|
|
44
|
-
|
|
45
|
-
Notes:
|
|
46
|
-
|
|
47
|
-
- Because `clear` takes a param, it's import that you don't pass it directly to an event handler,
|
|
48
|
-
e.g. `<Button onClick={clear} />` will not work as expected.
|
|
49
|
-
- Calling `set` after the interval has been cleared will restart the interval.
|
|
50
|
-
- Updating the second paramter, `timeoutMs`, will also restart the interval.
|
|
51
|
-
- When the component using this hooks is unmounted, the interval will automatically be cleared.
|
|
52
|
-
- Calling `set` after the interval is already set does nothing.
|
|
53
|
-
|
|
54
|
-
export const Immediately = () => {
|
|
55
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
56
|
-
const callback = React.useCallback(() => {
|
|
57
|
-
setCallCount((callCount) => callCount + 1);
|
|
58
|
-
}, []);
|
|
59
|
-
const interval = useScheduledInterval(callback, 1000);
|
|
60
|
-
return (
|
|
61
|
-
<View>
|
|
62
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
63
|
-
<View>callCount = {callCount}</View>
|
|
64
|
-
<View style={{flexDirection: "row"}}>
|
|
65
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
66
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
67
|
-
</View>
|
|
68
|
-
</View>
|
|
69
|
-
);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
<Canvas>
|
|
73
|
-
<Story name="Immediately">
|
|
74
|
-
<Immediately />
|
|
75
|
-
</Story>
|
|
76
|
-
</Canvas>
|
|
77
|
-
|
|
78
|
-
```jsx
|
|
79
|
-
const Immediately = () => {
|
|
80
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
81
|
-
const callback = React.useCallback(() => {
|
|
82
|
-
setCallCount((callCount) => callCount + 1);
|
|
83
|
-
}, []);
|
|
84
|
-
const interval = useScheduledInterval(callback, 1000);
|
|
85
|
-
return (
|
|
86
|
-
<View>
|
|
87
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
88
|
-
<View>callCount = {callCount}</View>
|
|
89
|
-
<View style={{flexDirection: "row"}}>
|
|
90
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
91
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
92
|
-
</View>
|
|
93
|
-
</View>
|
|
94
|
-
);
|
|
95
|
-
};
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
export const OnDemandAndResolveOnClear = () => {
|
|
99
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
100
|
-
const callback = React.useCallback(() => {
|
|
101
|
-
console.log("action called");
|
|
102
|
-
setCallCount((callCount) => callCount + 1);
|
|
103
|
-
}, []);
|
|
104
|
-
const interval = useScheduledInterval(callback, 1000, {
|
|
105
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
106
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
107
|
-
});
|
|
108
|
-
return (
|
|
109
|
-
<View>
|
|
110
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
111
|
-
<View>callCount = {callCount}</View>
|
|
112
|
-
<View style={{flexDirection: "row"}}>
|
|
113
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
114
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
115
|
-
</View>
|
|
116
|
-
</View>
|
|
117
|
-
);
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
<Canvas>
|
|
121
|
-
<Story name="OnDemandAndResolveOnClear">
|
|
122
|
-
<OnDemandAndResolveOnClear />
|
|
123
|
-
</Story>
|
|
124
|
-
</Canvas>
|
|
125
|
-
|
|
126
|
-
```jsx
|
|
127
|
-
const OnDemandAndResolveOnClear = () => {
|
|
128
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
129
|
-
const callback = React.useCallback(() => {
|
|
130
|
-
setCallCount((callCount) => callCount + 1);
|
|
131
|
-
}, []);
|
|
132
|
-
const interval = useScheduledInterval(callback, 1000, {
|
|
133
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
134
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
135
|
-
});
|
|
136
|
-
return (
|
|
137
|
-
<View>
|
|
138
|
-
<View>isSet = {interval.isSet.toString()}</View>
|
|
139
|
-
<View>callCount = {callCount}</View>
|
|
140
|
-
<View style={{flexDirection: "row"}}>
|
|
141
|
-
<Button onClick={() => interval.set()}>Set interval</Button>
|
|
142
|
-
<Button onClick={() => interval.clear()}>Clear interval</Button>
|
|
143
|
-
</View>
|
|
144
|
-
</View>
|
|
145
|
-
);
|
|
146
|
-
};
|
|
147
|
-
```
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {ClearPolicy, SchedulePolicy} from "../../util/policies.js";
|
|
8
|
-
import {useScheduledTimeout} from "@khanacademy/wonder-blocks-timing";
|
|
9
|
-
|
|
10
|
-
<Meta
|
|
11
|
-
title="Timing/useScheduledTimeout"
|
|
12
|
-
parameters={{
|
|
13
|
-
chromatic: {
|
|
14
|
-
disableSnapshot: true,
|
|
15
|
-
},
|
|
16
|
-
}}
|
|
17
|
-
/>
|
|
18
|
-
|
|
19
|
-
# `useScheduledTimeout`
|
|
20
|
-
|
|
21
|
-
`useScheduledTimeout` is a hook that provides a convenient API for setting and clearing
|
|
22
|
-
a timeout. It is defined as follows:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
function useScheduledTimeout(
|
|
26
|
-
action: () => mixed,
|
|
27
|
-
timeoutMs: number,
|
|
28
|
-
options?: {|
|
|
29
|
-
schedulePolicy?: "schedule-immediately" | "schedule-on-demand",
|
|
30
|
-
clearPolicy?: "resolve-on-clear" | "cancel-on-clear",
|
|
31
|
-
|},
|
|
32
|
-
): ITimeout;
|
|
33
|
-
|
|
34
|
-
interface ITimeout {
|
|
35
|
-
get isSet(): boolean;
|
|
36
|
-
set(): void;
|
|
37
|
-
clear(policy?: ClearPolicy): void;
|
|
38
|
-
}
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
By default the timeout will be set immediately up creation. The `options` parameter can
|
|
42
|
-
be used to control when when the timeout is schedule and whether or not `action` should be
|
|
43
|
-
called when the timeout is cleared.
|
|
44
|
-
|
|
45
|
-
Notes:
|
|
46
|
-
|
|
47
|
-
- Because `clear` takes a param, it's import that you don't pass it directly to an event handler,
|
|
48
|
-
e.g. `<Button onClick={clear} />` will not work as expected.
|
|
49
|
-
- Calling `set` after the timeout has expired will restart the timeout.
|
|
50
|
-
- Updating the second paramter, `timeoutMs`, will also restart the timeout.
|
|
51
|
-
- When the component using this hooks is unmounted, the timeout will automatically be cleared.
|
|
52
|
-
- Calling `set` after the timeout is set but before it expires means that the timeout will be
|
|
53
|
-
reset and will call `action`, `timeoutMs` after the most recent call to `set` was made.
|
|
54
|
-
|
|
55
|
-
export const Immediately = () => {
|
|
56
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
57
|
-
const callback = React.useCallback(() => {
|
|
58
|
-
setCallCount((callCount) => callCount + 1);
|
|
59
|
-
}, []);
|
|
60
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000);
|
|
61
|
-
return (
|
|
62
|
-
<View>
|
|
63
|
-
<View>isSet = {isSet.toString()}</View>
|
|
64
|
-
<View>callCount = {callCount}</View>
|
|
65
|
-
<View style={{flexDirection: "row"}}>
|
|
66
|
-
<Button onClick={set}>Set timeout</Button>
|
|
67
|
-
<Button onClick={clear}>Clear timeout</Button>
|
|
68
|
-
</View>
|
|
69
|
-
</View>
|
|
70
|
-
);
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
<Canvas>
|
|
74
|
-
<Story name="Immediately">
|
|
75
|
-
<Immediately />
|
|
76
|
-
</Story>
|
|
77
|
-
</Canvas>
|
|
78
|
-
|
|
79
|
-
```jsx
|
|
80
|
-
const Immediately = () => {
|
|
81
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
82
|
-
const callback = React.useCallback(() => {
|
|
83
|
-
setCallCount((callCount) => callCount + 1);
|
|
84
|
-
}, []);
|
|
85
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000);
|
|
86
|
-
return (
|
|
87
|
-
<View>
|
|
88
|
-
<View>isSet = {isSet.toString()}</View>
|
|
89
|
-
<View>callCount = {callCount}</View>
|
|
90
|
-
<View style={{flexDirection: "row"}}>
|
|
91
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
92
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
93
|
-
</View>
|
|
94
|
-
</View>
|
|
95
|
-
);
|
|
96
|
-
};
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
export const OnDemandAndResolveOnClear = () => {
|
|
100
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
101
|
-
const callback = React.useCallback(() => {
|
|
102
|
-
console.log("action called");
|
|
103
|
-
setCallCount((callCount) => callCount + 1);
|
|
104
|
-
}, []);
|
|
105
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000, {
|
|
106
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
107
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
108
|
-
});
|
|
109
|
-
return (
|
|
110
|
-
<View>
|
|
111
|
-
<View>isSet = {isSet.toString()}</View>
|
|
112
|
-
<View>callCount = {callCount}</View>
|
|
113
|
-
<View style={{flexDirection: "row"}}>
|
|
114
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
115
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
116
|
-
</View>
|
|
117
|
-
</View>
|
|
118
|
-
);
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
<Canvas>
|
|
122
|
-
<Story name="OnDemandAndResolveOnClear">
|
|
123
|
-
<OnDemandAndResolveOnClear />
|
|
124
|
-
</Story>
|
|
125
|
-
</Canvas>
|
|
126
|
-
|
|
127
|
-
```jsx
|
|
128
|
-
const OnDemandAndResolveOnClear = () => {
|
|
129
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
130
|
-
const callback = React.useCallback(() => {
|
|
131
|
-
setCallCount((callCount) => callCount + 1);
|
|
132
|
-
}, []);
|
|
133
|
-
const {isSet, set, clear} = useScheduledTimeout(callback, 1000, {
|
|
134
|
-
clearPolicy: ClearPolicy.Resolve,
|
|
135
|
-
schedulePolicy: SchedulePolicy.OnDemand,
|
|
136
|
-
});
|
|
137
|
-
return (
|
|
138
|
-
<View>
|
|
139
|
-
<View>isSet = {isSet.toString()}</View>
|
|
140
|
-
<View>callCount = {callCount}</View>
|
|
141
|
-
<View style={{flexDirection: "row"}}>
|
|
142
|
-
<Button onClick={() => set()}>Set timeout</Button>
|
|
143
|
-
<Button onClick={() => clear()}>Clear timeout</Button>
|
|
144
|
-
</View>
|
|
145
|
-
</View>
|
|
146
|
-
);
|
|
147
|
-
};
|
|
148
|
-
```
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
import {Meta, Story, Source, Canvas} from "@storybook/addon-docs";
|
|
2
|
-
|
|
3
|
-
import {Body, HeadingSmall} from "@khanacademy/wonder-blocks-typography";
|
|
4
|
-
import {View} from "@khanacademy/wonder-blocks-core";
|
|
5
|
-
import Button from "@khanacademy/wonder-blocks-button";
|
|
6
|
-
|
|
7
|
-
import {useTimeout} from "@khanacademy/wonder-blocks-timing";
|
|
8
|
-
|
|
9
|
-
<Meta
|
|
10
|
-
title="Timing/useTimeout"
|
|
11
|
-
parameters={{
|
|
12
|
-
chromatic: {
|
|
13
|
-
disableSnapshot: true,
|
|
14
|
-
},
|
|
15
|
-
}}
|
|
16
|
-
/>
|
|
17
|
-
|
|
18
|
-
# `useTimeout`
|
|
19
|
-
|
|
20
|
-
`useTimeout` is a hook that provides a simple API for using timers safely.
|
|
21
|
-
It is defined as follows:
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
function useTimeout(
|
|
25
|
-
action: () => mixed,
|
|
26
|
-
timeoutMs: number,
|
|
27
|
-
active: boolean,
|
|
28
|
-
): void;
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
Notes:
|
|
32
|
-
|
|
33
|
-
- Setting `active` to `true` will start the timeout and setting it to `false`
|
|
34
|
-
will stop it
|
|
35
|
-
- Changing the value of `timeoutMs` will reset the timeout, changing `action`
|
|
36
|
-
will not.
|
|
37
|
-
|
|
38
|
-
export const BasicUsage = () => {
|
|
39
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
40
|
-
const [active, setActive] = React.useState(false);
|
|
41
|
-
const callback = React.useCallback(() => {
|
|
42
|
-
setCallCount((callCount) => callCount + 1);
|
|
43
|
-
}, []);
|
|
44
|
-
useTimeout(callback, 1000, active);
|
|
45
|
-
return (
|
|
46
|
-
<View>
|
|
47
|
-
<View>callCount = {callCount}</View>
|
|
48
|
-
<View>active = {active.toString()}</View>
|
|
49
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
50
|
-
Toggle active
|
|
51
|
-
</Button>
|
|
52
|
-
</View>
|
|
53
|
-
);
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
<Canvas>
|
|
57
|
-
<Story name="BasicUsage">
|
|
58
|
-
<BasicUsage />
|
|
59
|
-
</Story>
|
|
60
|
-
</Canvas>
|
|
61
|
-
|
|
62
|
-
```jsx
|
|
63
|
-
export const BasicUsage = () => {
|
|
64
|
-
const [callCount, setCallCount] = React.useState(0);
|
|
65
|
-
const [active, setActive] = React.useState(false);
|
|
66
|
-
const callback = React.useCallback(() => {
|
|
67
|
-
setCallCount((callCount) => callCount + 1);
|
|
68
|
-
}, []);
|
|
69
|
-
useTimeout(callback, 1000, active);
|
|
70
|
-
return (
|
|
71
|
-
<View>
|
|
72
|
-
<View>callCount = {callCount}</View>
|
|
73
|
-
<View>active = {active.toString()}</View>
|
|
74
|
-
<Button onClick={() => setActive(!active)} style={{width: 200}}>
|
|
75
|
-
Toggle active
|
|
76
|
-
</Button>
|
|
77
|
-
</View>
|
|
78
|
-
);
|
|
79
|
-
};
|
|
80
|
-
```
|