Skip to content

Commit de80b15

Browse files
committed
Update tests and readme
1 parent 59539ad commit de80b15

File tree

6 files changed

+135
-29
lines changed

6 files changed

+135
-29
lines changed

jest.setup.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

lib/__tests__/test.tsx

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import 'regenerator-runtime/runtime';
22
import {isDone, isLoading, isReloading, LState, useLoadingSteps} from "../index";
33
import React, {useMemo} from "react";
4-
import {createTestComponent, noop, wait} from "../test_util";
4+
import {createTestComponent, neverCalled, wait} from "../test_util";
55

66
describe('no delay', () => {
77
it('initial loaded = true', async () => {
@@ -37,7 +37,7 @@ describe('no delay', () => {
3737

3838
it('single step', async () => {
3939
let expectedState: LState;
40-
let setStepDoneCb: (s: string) => void = noop;
40+
let setStepDoneCb: (s: string) => void = neverCalled;
4141

4242
// Do before creating test component
4343
const doSteps = async () => {
@@ -58,12 +58,13 @@ describe('no delay', () => {
5858
it('multiple steps', async () => {
5959
const stepCnt = 3;
6060
let expectedState: LState;
61-
let setStepDoneCb: (s: string) => void = noop;
61+
let setStepDoneCb: (s: string) => void = neverCalled;
6262

6363
// Do before creating test component
6464
const doSteps = async () => {
6565
expectedState = LState.LOADING;
6666

67+
await wait(10);
6768
for (let i = 0; i < stepCnt; i++) {
6869
if (i == stepCnt - 1) {
6970
expectedState = LState.DONE;
@@ -80,6 +81,39 @@ describe('no delay', () => {
8081
useMemo(() => expect(loadingState).toEqual(expectedState), [loadingState]);
8182
});
8283
});
84+
85+
it('multiple steps: skip step', async () => {
86+
const stepCnt = 3;
87+
let expectedState: LState;
88+
let setStepDoneCb: (s: string) => void = neverCalled;
89+
let skipStepCb: (s: string) => void = neverCalled;
90+
91+
// Do before creating test component
92+
const doSteps = async () => {
93+
expectedState = LState.LOADING;
94+
95+
await wait(10);
96+
for (let i = 0; i < stepCnt; i++) {
97+
if (i == stepCnt - 1) {
98+
expectedState = LState.DONE;
99+
}
100+
if (i % 2 === 0) {
101+
setStepDoneCb(`step${i + 1}`);
102+
} else {
103+
skipStepCb(`step${i + 1}`);
104+
}
105+
await wait(10); // pause shortly for event loop to run component logics
106+
}
107+
}
108+
doSteps().then();
109+
110+
await createTestComponent(() => {
111+
const [loadingState, setStepDone, _, skipStep] = useLoadingSteps(stepCnt, false);
112+
setStepDoneCb = setStepDone;
113+
skipStepCb = skipStep;
114+
useMemo(() => expect(loadingState).toEqual(expectedState), [loadingState]);
115+
});
116+
});
83117
});
84118

85119
describe('with render delay', () => {
@@ -96,7 +130,7 @@ describe('with render delay', () => {
96130

97131
it('single step', async () => {
98132
let expectedState: LState;
99-
let setStepDoneCb: (s: string) => void = noop;
133+
let setStepDoneCb: (s: string) => void = neverCalled;
100134

101135
// Do before creating test component
102136
const doSteps = async () => {
@@ -122,7 +156,7 @@ describe('with render delay', () => {
122156

123157
it('multiple steps', async () => {
124158
let expectedState: LState;
125-
let setStepDoneCb: (s: string) => void = noop;
159+
let setStepDoneCb: (s: string) => void = neverCalled;
126160

127161
// Do before creating test component
128162
const doSteps = async () => {
@@ -151,7 +185,7 @@ describe('with render delay', () => {
151185

152186
it('multiple steps: done before render delay timeout', async () => {
153187
let expectedState: LState;
154-
let setStepDoneCb: (s: string) => void = noop;
188+
let setStepDoneCb: (s: string) => void = neverCalled;
155189

156190
// Do before creating test component
157191
const doSteps = async () => {
@@ -183,8 +217,8 @@ describe('with reset delay', () => {
183217

184218
it('multiple steps', async () => {
185219
let expectedState: LState;
186-
let setStepDoneCb: (s: string) => void = noop;
187-
let resetLoadingCb: () => void = noop;
220+
let setStepDoneCb: (s: string) => void = neverCalled;
221+
let resetLoadingCb: () => void = neverCalled;
188222

189223
// Do before creating test component
190224
const doSteps = async () => {
@@ -228,8 +262,8 @@ describe('with render delay + reset delay', () => {
228262

229263
it('multiple steps', async () => {
230264
let expectedState: LState;
231-
let setStepDoneCb: (s: string) => void = noop;
232-
let resetLoadingCb: () => void = noop;
265+
let setStepDoneCb: (s: string) => void = neverCalled;
266+
let resetLoadingCb: () => void = neverCalled;
233267

234268
// Do before creating test component
235269
const doSteps = async () => {
@@ -276,7 +310,7 @@ describe('with done delay', () => {
276310

277311
it('multiple steps', async () => {
278312
let expectedState: LState;
279-
let setStepDoneCb: (s: string) => void = noop;
313+
let setStepDoneCb: (s: string) => void = neverCalled;
280314

281315
// Do before creating test component
282316
const doSteps = async () => {

lib/test_util.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export async function wait(period: number): Promise<void> {
66
return period > 0 ? new Promise(resolve => setTimeout(resolve, period)) : Promise.resolve();
77
}
88

9-
export function noop() {}
9+
export function neverCalled() {
10+
throw new Error('This function should not be called');
11+
}
1012

1113
export async function createTestComponent(logic: () => void, waitToFinish = 100) {
1214
const Component = ({}): React.ReactElement | null => {

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
],
99
"author": "@edingroot",
1010
"repository": "edingroot/use-loading-steps",
11-
"version": "0.2.0",
11+
"version": "0.2.1",
1212
"main": "dist/index.js",
1313
"types": "dist/index.d.ts",
1414
"module": "dist/index.modern.js",

readme.md

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,90 @@
11
# use-loading-steps
2-
32
[![npm version](https://badge.fury.io/js/use-loading-steps.svg)](https://www.npmjs.com/package/use-loading-steps)
43

5-
Tutorial work in progress...
4+
A simple state management library for smooth react page loading experience.
5+
6+
7+
## Install
8+
```bash
9+
yarn add use-loading-steps
10+
# or
11+
npm install --save use-loading-steps
12+
```
13+
14+
15+
## Usage
16+
```javascript
17+
const [loadingState, setStepDone, resetLoading, skipStep] = useLoadingSteps(taskCount, initLoaded, options);
18+
```
19+
*useLoadingSteps* hook params
20+
- `taskCount`: the number of steps should be done before the page is loaded.
21+
- `initLoaded`: set to true to skip all state transitions, loadingState = `DONE`.
22+
- `options`: see below.
23+
24+
Hook returns
25+
- `loadingState`: the state, type: `LState` enum (string).
26+
- `setStepDone('step_name')`: to be called when a step is finished, step_name should be a unique string.
27+
- `resetLoading()`: to be called when reloading resources.
28+
- `skipStep('step_name)`: same effect as setStepDone, but prints different debug log.
29+
30+
Options
31+
```typescript
32+
interface Options {
33+
renderDelay?: number; // timeout of SILENT_LOADING state after started
34+
resetDelay?: number; // timeout of SILENT_LOADING state after reset
35+
doneDelay?: number; // timeout of DELAY_DONE state
36+
name?: string; // for debug log (useful if there are multiple pages / components use this hook)
37+
}
38+
```
39+
The debug log is printed by `console.debug`, and is skipped in production build.
40+
41+
42+
## Loading States
43+
```typescript
44+
export enum LState {
45+
SILENT_LOADING = 'SILENT_LOADING', // for: do loading but not to show loading animation
46+
LOADING = 'LOADING', // for: show loading animation
47+
DELAY_DONE = 'DELAY_DONE', // for: loading finished but keep showing loading animation
48+
DONE = 'DONE', // for: all ready
49+
}
50+
```
51+
52+
Utility functions
53+
```typescript
54+
export const isLoading = (state: LState) => LState.LOADING === state;
55+
export const isReloading = (state: LState) => [LState.SILENT_LOADING, LState.LOADING].includes(state);
56+
export const isDone = (state: LState) => LState.DONE === state;
57+
```
58+
59+
60+
## Example
61+
62+
```javascript
63+
// Number of steps: 2, loaded: false, renderDelay: 100ms
64+
const [loadingState, setStepDone] = useLoadingSteps(2, false, {renderDelay: 100});
65+
const [rows, setRows] = useState([]);
66+
67+
useEffect(async () => {
68+
const data = await fetchData();
69+
setStepDone('fetch');
70+
71+
const rows = await transformData(data);
72+
setStepDone('transform');
73+
}, []);
74+
75+
if (isLoading(loadingState)) {
76+
return <div>(Loading animation)</div>;
77+
}
78+
return (
79+
<div>
80+
{data.map((item) => <div>row: {item}</div>)}
81+
</div>
82+
);
83+
```
84+
Explanation
85+
- Initialize, if loaded = false, state => `SILENT_LOADING`, isLoading(loadingState) = false
86+
- After 100ms, if not finished, state => `LOADING`, isLoading(loadingState) = true
87+
- After the two `setStepDone('step name')` are called, state => `DONE`, isLoading(loadingState) = false
688

89+
More examples
90+
- Please refer to unit tests in `lib/__test__`.

tslint.json

Lines changed: 0 additions & 13 deletions
This file was deleted.

0 commit comments

Comments
 (0)