Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"name": "rax-hooks",
"private": true,
"description": "Contains rax hooks that are used very frequently",
"scripts": {
"start": "npm run clean && node ./scripts/compile-packages.js --watch",
Expand All @@ -20,6 +21,9 @@
"rax",
"hooks"
],
"workspaces": [
"packages/*"
],
"config": {
"ghooks": {
"commit-msg": "./scripts/validate-commit-msg.js"
Expand Down Expand Up @@ -70,7 +74,7 @@
"lerna": "^3.19.0",
"minimatch": "^3.0.4",
"minimist": "^1.2.0",
"rax": "^1.1.0",
"rax": "1.1.4",
"rax-test-renderer": "^1.0.0",
"semver": "^7.1.2",
"semver-regex": "^2.0.0",
Expand Down
35 changes: 26 additions & 9 deletions packages/useCountDown/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<img src="https://img.shields.io/npm/v/rax-use-countdown.svg" alt="npm package" />
<img src="https://img.shields.io/npm/dm/rax-use-countdown.svg" alt="npm downloads" />

A countdown hooks which will return the left days/hours/minutes/seconds state.
A countdown hooks which will return the left time(in millisecond).

## Install

Expand All @@ -12,23 +12,40 @@ $ npm install rax-use-countdown --save

## API

The API will recevie two params -- `start`/`end`.
The API will recevie two params -- `timeToCount`/`interval`.

| | Type | Description |
| ----- | -------- | ----------- |
| start | `number` | Start time |
| ent | `number` | End time |
| timeToCount | `number` | total time to count, in millisecond |
| interval | `number` | interval time on every tick, in millisecond |
| events | `object` | onStart, onTick, onPause, onResume, onCompleted, onReset |

## Example

```jsx
import { createElement } from 'rax';
import { createElement, useEffect } from 'rax';
import useCountDown from 'rax-use-countdown';

function Example() {
const now = Date.now();
const { days, hours, minutes, seconds } = useCountDown(now, now - 10000000);

return <div>There only left {days}days {hours}hours {minutes}minutes {seconds}seconds</div>;
// countdown 10s with 100ms interval
const [timeLeft, { start, pause, resume, reset }] = useCountDown(10 * 1000, 100, {
onStart() {},
onTick(timeLeft) {
// countdown tick, unit of `timeLeft` is millisecond
},
onPause() {},
onResume() {},
onCompleted() {
// countdown completed
},
onReset() {}
});

useEffect(() => {
start();
}, []);

// you can format timeLeft by yourself
return <div>There only left { timeLeft } milliseconds</div>;
}
```
2 changes: 1 addition & 1 deletion packages/useCountDown/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "rax-use-countdown",
"version": "1.0.2",
"version": "2.0.0",
"description": "Rax useCountDown hook",
"license": "BSD-3-Clause",
"main": "lib/index.js",
Expand Down
189 changes: 182 additions & 7 deletions packages/useCountDown/src/__tests__/useCountDown.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createElement } from 'rax';
import { createElement, useEffect } from 'rax';
import renderer from 'rax-test-renderer';
import useCountDown from '..';

Expand All @@ -13,21 +13,196 @@ function asyncFn(delay, val) {
describe('useCountDown', () => {
it('3 seconds count down', async() => {
function App() {
const now = Date.now();
const { days, hours, minutes, seconds } = useCountDown(now + 3000, now);
const [timeLeft, { start }] = useCountDown(3 * 1000, 1000);

return <div>{days}:{hours}:{minutes}:{seconds}</div>;
useEffect(() => {
start();
}, []);

return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(200);
expect(tree.toJSON().children.join('')).toEqual('3000');

await asyncFn(1000);
expect(tree.toJSON().children.join('')).toEqual('2000');

await asyncFn(2000);
expect(tree.toJSON().children.join('')).toEqual('0');
});

it('100ms interval', async() => {
function App() {
const [timeLeft, { start }] = useCountDown(1000, 100);

useEffect(() => {
start();
}, []);

return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(50);
expect(tree.toJSON().children.join('')).toEqual('1000');

await asyncFn(100);
expect(tree.toJSON().children.join('')).toEqual('900');

await asyncFn(100);
expect(tree.toJSON().children.join('')).toEqual('800');

await asyncFn(700);
expect(tree.toJSON().children.join('')).toEqual('100');

await asyncFn(100);
expect(tree.toJSON().children.join('')).toEqual('0');
});

it('pause', async() => {
const mockPause = jest.fn();
function App() {
const [timeLeft, { start, pause }] = useCountDown(1000, 100, {
onPause: mockPause,
});

useEffect(() => {
start();

setTimeout(() => pause(), 550);
}, []);

return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(150);
expect(tree.toJSON().children.join('')).toEqual('900');

await asyncFn(500);
expect(tree.toJSON().children.join('')).toEqual('500');
await asyncFn(500);
expect(tree.toJSON().children.join('')).toEqual('500');
expect(mockPause).toHaveBeenCalledTimes(1);
});

it('resume', async() => {
const mockPause = jest.fn();
const mockResume = jest.fn();
function App() {
const [timeLeft, { start, pause, resume }] = useCountDown(1000, 100, {
onPause: mockPause,
onResume: mockResume,
});

useEffect(() => {
start();

setTimeout(() => pause(), 550);
setTimeout(() => resume(), 1100);
}, []);

expect(tree.toJSON().children.join('')).toEqual('0:0:0:3');
return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(150);
expect(tree.toJSON().children.join('')).toEqual('900');

await asyncFn(500);
expect(tree.toJSON().children.join('')).toEqual('500');

// still paused
await asyncFn(100);
expect(tree.toJSON().children.join('')).toEqual('500');

await asyncFn(500);
expect(tree.toJSON().children.join('')).toEqual('400');
await asyncFn(450);
expect(tree.toJSON().children.join('')).toEqual('0');

expect(mockPause).toHaveBeenCalledTimes(1);
expect(mockResume).toHaveBeenCalledTimes(1);
});

it('reset', async() => {
const mockReset = jest.fn();

function App() {
const [timeLeft, { start, reset }] = useCountDown(1000, 100, {
onReset: mockReset,
});

useEffect(() => {
start();
setTimeout(() => reset(), 550);
}, []);

return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(150);

expect(tree.toJSON().children.join('')).toEqual('900');

await asyncFn(500);
expect(tree.toJSON().children.join('')).toEqual('1000');

await asyncFn(100);
expect(tree.toJSON().children.join('')).toEqual('1000');

expect(mockReset).toHaveBeenCalledTimes(1);
});

it('events', async() => {
const mockStart = jest.fn();
const mockTick = jest.fn();
const mockCompleted = jest.fn();
function App() {
const [timeLeft, { start }] = useCountDown(1000, 100, {
onStart: mockStart,
onTick: mockTick,
onCompleted: mockCompleted,
});

useEffect(() => {
start();
}, []);

return <div>{timeLeft}</div>;
}

const tree = renderer.create(<App />);

// For render
await asyncFn(1100);

await asyncFn(3000);
expect(mockStart).toHaveBeenCalledTimes(1);
expect(mockCompleted).toHaveBeenCalledTimes(1);

expect(tree.toJSON().children.join('')).toEqual('0:0:0:0');
expect(mockTick).toHaveBeenCalledTimes(10);
expect(mockTick).toHaveBeenNthCalledWith(1, 1000);
expect(mockTick).toHaveBeenNthCalledWith(2, 900);
expect(mockTick).toHaveBeenNthCalledWith(3, 800);
expect(mockTick).toHaveBeenNthCalledWith(4, 700);
expect(mockTick).toHaveBeenNthCalledWith(5, 600);
expect(mockTick).toHaveBeenNthCalledWith(6, 500);
expect(mockTick).toHaveBeenNthCalledWith(7, 400);
expect(mockTick).toHaveBeenNthCalledWith(8, 300);
expect(mockTick).toHaveBeenNthCalledWith(9, 200);
expect(mockTick).toHaveBeenNthCalledWith(10, 100);
});
});
Loading