├── .cz.json
├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ ├── feature_request.md
│ └── other.md
└── workflows
│ └── on_push.yml
├── .gitignore
├── .npmignore
├── .run
├── Commit.run.xml
├── Prettier check.run.xml
├── Prettier write.run.xml
├── Run Integration Tests.run.xml
└── Run Unit Tests.run.xml
├── .versionrc.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── docs
├── _assets
│ └── css
│ │ └── style.scss
├── _config.yml
├── boilerplate.md
├── callbacks
│ ├── index.md
│ ├── useAnimationFrame.md
│ ├── useDebounce.md
│ ├── useIdleCallback.md
│ ├── useThrottle.md
│ └── useTimeout.md
├── effects
│ ├── index.md
│ ├── useIdleCallbackEffect.md
│ └── useTimeoutEffect.md
├── index.md
├── list-of-all-hooks
│ └── index.md
├── loops-and-intervals
│ ├── index.md
│ ├── useAnimationFrameLoop.md
│ ├── useClock.md
│ ├── useCountdown.md
│ ├── useCounter.md
│ ├── useInterval.md
│ ├── useOscillator.md
│ └── useTimer.md
├── migrations
│ ├── index.md
│ ├── v1v2.md
│ ├── v2v3.md
│ ├── v3v4.md
│ └── v4v5.md
└── state
│ ├── index.md
│ └── useThrottledState.md
├── integration-tests
├── helpers.ts
├── useAnimationFrame.test.tsx
├── useAnimationFrameLoop.test.tsx
├── useClock.test.tsx
├── useCountdown.test.tsx
├── useDebounce.test.tsx
├── useIdleCallback.test.tsx
├── useIdleCallbackEffect.test.tsx
├── useInterval.test.tsx
├── useOscillator.test.tsx
├── useThrottledState.test.tsx
├── useTimeout.test.tsx
├── useTimeoutEffect.test.tsx
└── useTimer.test.tsx
├── jest.config.js
├── jest.setup.js
├── logo.png
├── package-lock.json
├── package.json
├── prettier.config.js
├── rollup.config.js
├── rollup.config.prod.js
├── src
├── animation-frame
│ ├── types.ts
│ ├── useAnimationFrame.test.ts
│ ├── useAnimationFrame.ts
│ ├── useAnimationFrameLoop.test.ts
│ └── useAnimationFrameLoop.ts
├── controls
│ ├── useControls.test.ts
│ └── useControls.ts
├── general-utility
│ └── useThrottledState.ts
├── idle-callback
│ ├── types.ts
│ ├── useIdleCallback.test.ts
│ ├── useIdleCallback.ts
│ ├── useIdleCallbackEffect.test.ts
│ └── useIdleCallbackEffect.ts
├── index.ts
├── interval
│ ├── useClock.test.ts
│ ├── useClock.ts
│ ├── useCountdown.test.ts
│ ├── useCountdown.ts
│ ├── useCounter.test.ts
│ ├── useCounter.ts
│ ├── useInterval.test.ts
│ ├── useInterval.ts
│ ├── useOscillator.test.ts
│ ├── useOscillator.ts
│ ├── useTimer.test.ts
│ └── useTimer.ts
├── testing
│ └── advanceTimersUsingAct.ts
├── timeout
│ ├── types.ts
│ ├── useDebounce.test.ts
│ ├── useDebounce.ts
│ ├── useThrottle.test.ts
│ ├── useThrottle.ts
│ ├── useTimeout.test.ts
│ ├── useTimeout.ts
│ ├── useTimeoutEffect.test.ts
│ └── useTimeoutEffect.ts
└── util
│ └── logging.ts
└── tsconfig.json
/.cz.json:
--------------------------------------------------------------------------------
1 | {
2 | "path": "node_modules/emoji-cz",
3 | "emoji-cz": {
4 | "types": {
5 | "Fix": {
6 | "name": "fix"
7 | },
8 | "Feat": {
9 | "name": "feat"
10 | },
11 | "Docs": {
12 | "name": "docs",
13 | "emoji": "📝"
14 | },
15 | "Style": {
16 | "name": "style",
17 | "description": "White-space, formatting, missing semi-colons..."
18 | },
19 | "Refactor": {
20 | "emoji": "♻️",
21 | "name": "refactor"
22 | },
23 | "Perf": {
24 | "emoji": "⚡",
25 | "name": "perf"
26 | },
27 | "Test": {
28 | "emoji": "🚨",
29 | "description": "Adding missing tests or correcting existing tests",
30 | "name": "test"
31 | },
32 | "Chore": {
33 | "emoji": "🔧",
34 | "name": "chore",
35 | "description": "Auxiliary tool changes, configs, dev-ops etc."
36 | },
37 | "CI": {
38 | "emoji": "🚀",
39 | "name": "ci",
40 | "description": "Changes to the build pipeline"
41 | }
42 | },
43 | "format": "[name]: [emoji] [subject]"
44 | }
45 | }
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | [*]
2 | charset=utf-8
3 | insert_final_newline=true
4 | indent_style=space
5 | indent_size=2
6 | tab_width=2
7 |
8 | [*.{js,ts}]
9 | indent_style=space
10 | tab_width=2
11 | ij_javascript_force_semicolon_style = false
12 | ij_javascript_use_semicolon_after_statement = false
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: EricLambrecht
7 |
8 | ---
9 |
10 | **Bug Description:**
11 | A clear and concise description of the bug / problem / issue.
12 |
13 | **To Reproduce:**
14 | Steps to reproduce the buggy behavior. A code example would be very helpful.
15 |
16 | **Expected behavior:**
17 | A clear and concise description of what you expected to happen instead.
18 |
19 | **Screenshots:**
20 | If applicable, add screenshots to help explain your problem.
21 |
22 | **System:**
23 | - Node Version: [e.g. 16.13.2 LTS]
24 | - OS: [e.g. macOS]
25 | - Browser? [e.g. chrome 67, safari 12]
26 |
27 | **Additional context:**
28 | Add any other context about the problem here.
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Status Quo / Problem / Topic**
11 | Description of the status quo / a problem / a thing that needs improvement in your opinion.
12 |
13 | **Solution**
14 | A clear and concise description of a possible solution or what you want to happen. Code examples are welcome.
15 |
16 | **Additional context**
17 | Add any other context or screenshots about the feature request here.
18 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Other
3 | about: Anything that is not bug or feature related
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/workflows/on_push.yml:
--------------------------------------------------------------------------------
1 | name: React Timing Hooks – Build & Test
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | build:
6 | name: ${{ matrix.os }}, Node ${{ matrix.node-version }}
7 | runs-on: ${{ matrix.os }}
8 |
9 | strategy:
10 | matrix:
11 | os: [macos-latest, windows-latest, ubuntu-latest]
12 | node-version: [16.x, 18.x, 20.x]
13 |
14 | steps:
15 | - uses: actions/checkout@v1
16 | - name: Setup Node ${{ matrix.node-version }} on ${{ matrix.os }}
17 | uses: actions/setup-node@v1
18 | with:
19 | node-version: ${{ matrix.node-version }}
20 | - name: npm install
21 | run: npm ci
22 | - name: install locales for integration tests
23 | run: |
24 | npm install -g full-icu
25 | echo "NODE_ICU_DATA=`node-full-icu-path 2>/dev/null`" >> $GITHUB_ENV
26 | shell: bash
27 | - name: Lint and unit tests
28 | run: |
29 | npm run prettier:check
30 | npm run test:unit
31 | - name: Coveralls.io Test Coverage
32 | uses: coverallsapp/github-action@master
33 | with:
34 | github-token: ${{ secrets.GITHUB_TOKEN }}
35 | flag-name: run-${{ matrix.node-version }}-on-${{ matrix.os }}
36 | parallel: true
37 | - name: Integration tests
38 | run: |
39 | npm run build --if-present
40 | npm run test:integration
41 | env:
42 | CI: true
43 |
44 | finish:
45 | needs: build
46 | runs-on: ubuntu-latest
47 | steps:
48 | - name: Coveralls Finished
49 | uses: coverallsapp/github-action@master
50 | with:
51 | github-token: ${{ secrets.github_token }}
52 | parallel-finished: true
53 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Exclude JetBrains dir
2 | .idea/
3 |
4 | # dist folder
5 | dist/
6 | .tmp/
7 |
8 | # Created by .ignore support plugin (hsz.mobi)
9 | ### Node template
10 | # Logs
11 | logs
12 | *.log
13 | npm-debug.log*
14 | yarn-debug.log*
15 | yarn-error.log*
16 | lerna-debug.log*
17 |
18 | # Diagnostic reports (https://nodejs.org/api/report.html)
19 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
20 |
21 | # Runtime data
22 | pids
23 | *.pid
24 | *.seed
25 | *.pid.lock
26 |
27 | # Directory for instrumented libs generated by jscoverage/JSCover
28 | lib-cov
29 |
30 | # Coverage directory used by tools like istanbul
31 | coverage
32 | *.lcov
33 |
34 | # nyc test coverage
35 | .nyc_output
36 |
37 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
38 | .grunt
39 |
40 | # Bower dependency directory (https://bower.io/)
41 | bower_components
42 |
43 | # node-waf configuration
44 | .lock-wscript
45 |
46 | # Compiled binary addons (https://nodejs.org/api/addons.html)
47 | build/Release
48 |
49 | # Dependency directories
50 | node_modules/
51 | jspm_packages/
52 |
53 | # TypeScript v1 declaration files
54 | typings/
55 |
56 | # TypeScript cache
57 | *.tsbuildinfo
58 |
59 | # Optional npm cache directory
60 | .npm
61 |
62 | # Optional eslint cache
63 | .eslintcache
64 |
65 | # Optional REPL history
66 | .node_repl_history
67 |
68 | # Output of 'npm pack'
69 | *.tgz
70 |
71 | # Yarn Integrity file
72 | .yarn-integrity
73 |
74 | # dotenv environment variables file
75 | .env
76 | .env.test
77 |
78 | # parcel-bundler cache (https://parceljs.org/)
79 | .cache
80 |
81 | # next.js build output
82 | .next
83 |
84 | # nuxt.js build output
85 | .nuxt
86 |
87 | # vuepress build output
88 | .vuepress/dist
89 |
90 | # Serverless directories
91 | .serverless/
92 |
93 | # FuseBox cache
94 | .fusebox/
95 |
96 | # DynamoDB Local files
97 | .dynamodb/
98 |
99 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .*
2 | **/tsconfig.json
3 | **/prettier.config.js
4 | **/jest.config.js
5 | **/jest.setup.js
6 | **/rollup.config.js
7 | **/rollup.config.prod.js
8 | _*
9 |
10 | CODE_OF_CONDUCT.md
11 | CONTRIBUTING.md
12 | CHANGELOG.md
13 |
14 | .tmp
15 | coverage
16 | node_modules
17 | docs
18 | src
19 | integration-tests
20 | logo.png
21 |
--------------------------------------------------------------------------------
/.run/Commit.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.run/Prettier check.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.run/Prettier write.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.run/Run Integration Tests.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.run/Run Unit Tests.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.versionrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "types": [
3 | {"type": "feat", "section": "Features"},
4 | {"type": "fix", "section": "Bug Fixes"},
5 | {"type": "chore", "hidden": true},
6 | {"type": "docs", "hidden": true},
7 | {"type": "style", "hidden": true},
8 | {"type": "refactor", "hidden": true},
9 | {"type": "perf", "hidden": true},
10 | {"type": "test", "hidden": true}
11 | ]
12 | }
13 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | We as members, contributors, and leaders pledge to make participation in our
6 | community a harassment-free experience for everyone, regardless of age, body
7 | size, visible or invisible disability, ethnicity, sex characteristics, gender
8 | identity and expression, level of experience, education, socio-economic status,
9 | nationality, personal appearance, race, religion, or sexual identity
10 | and orientation.
11 |
12 | We pledge to act and interact in ways that contribute to an open, welcoming,
13 | diverse, inclusive, and healthy community.
14 |
15 | ## Our Standards
16 |
17 | Examples of behavior that contributes to a positive environment for our
18 | community include:
19 |
20 | * Demonstrating empathy and kindness toward other people
21 | * Being respectful of differing opinions, viewpoints, and experiences
22 | * Giving and gracefully accepting constructive feedback
23 | * Accepting responsibility and apologizing to those affected by our mistakes,
24 | and learning from the experience
25 | * Focusing on what is best not just for us as individuals, but for the
26 | overall community
27 |
28 | Examples of unacceptable behavior include:
29 |
30 | * The use of sexualized language or imagery, and sexual attention or
31 | advances of any kind
32 | * Trolling, insulting or derogatory comments, and personal or political attacks
33 | * Public or private harassment
34 | * Publishing others' private information, such as a physical or email
35 | address, without their explicit permission
36 | * Other conduct which could reasonably be considered inappropriate in a
37 | professional setting
38 |
39 | ## Enforcement Responsibilities
40 |
41 | Community leaders are responsible for clarifying and enforcing our standards of
42 | acceptable behavior and will take appropriate and fair corrective action in
43 | response to any behavior that they deem inappropriate, threatening, offensive,
44 | or harmful.
45 |
46 | Community leaders have the right and responsibility to remove, edit, or reject
47 | comments, commits, code, wiki edits, issues, and other contributions that are
48 | not aligned to this Code of Conduct, and will communicate reasons for moderation
49 | decisions when appropriate.
50 |
51 | ## Scope
52 |
53 | This Code of Conduct applies within all community spaces, and also applies when
54 | an individual is officially representing the community in public spaces.
55 | Examples of representing our community include using an official e-mail address,
56 | posting via an official social media account, or acting as an appointed
57 | representative at an online or offline event.
58 |
59 | ## Enforcement
60 |
61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
62 | reported to the community leaders responsible for enforcement at
63 | [mail@ericlambrecht.de](mail@ericlambrecht.de).
64 | All complaints will be reviewed and investigated promptly and fairly.
65 |
66 | All community leaders are obligated to respect the privacy and security of the
67 | reporter of any incident.
68 |
69 | ## Enforcement Guidelines
70 |
71 | Community leaders will follow these Community Impact Guidelines in determining
72 | the consequences for any action they deem in violation of this Code of Conduct:
73 |
74 | ### 1. Correction
75 |
76 | **Community Impact**: Use of inappropriate language or other behavior deemed
77 | unprofessional or unwelcome in the community.
78 |
79 | **Consequence**: A private, written warning from community leaders, providing
80 | clarity around the nature of the violation and an explanation of why the
81 | behavior was inappropriate. A public apology may be requested.
82 |
83 | ### 2. Warning
84 |
85 | **Community Impact**: A violation through a single incident or series
86 | of actions.
87 |
88 | **Consequence**: A warning with consequences for continued behavior. No
89 | interaction with the people involved, including unsolicited interaction with
90 | those enforcing the Code of Conduct, for a specified period of time. This
91 | includes avoiding interactions in community spaces as well as external channels
92 | like social media. Violating these terms may lead to a temporary or
93 | permanent ban.
94 |
95 | ### 3. Temporary Ban
96 |
97 | **Community Impact**: A serious violation of community standards, including
98 | sustained inappropriate behavior.
99 |
100 | **Consequence**: A temporary ban from any sort of interaction or public
101 | communication with the community for a specified period of time. No public or
102 | private interaction with the people involved, including unsolicited interaction
103 | with those enforcing the Code of Conduct, is allowed during this period.
104 | Violating these terms may lead to a permanent ban.
105 |
106 | ### 4. Permanent Ban
107 |
108 | **Community Impact**: Demonstrating a pattern of violation of community
109 | standards, including sustained inappropriate behavior, harassment of an
110 | individual, or aggression toward or disparagement of classes of individuals.
111 |
112 | **Consequence**: A permanent ban from any sort of public interaction within
113 | the community.
114 |
115 | ## Attribution
116 |
117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
118 | version 2.0, available at
119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
120 |
121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
122 | enforcement ladder](https://github.com/mozilla/diversity).
123 |
124 | [homepage]: https://www.contributor-covenant.org
125 |
126 | For answers to common questions about this code of conduct, see the FAQ at
127 | https://www.contributor-covenant.org/faq. Translations are available at
128 | https://www.contributor-covenant.org/translations.
129 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribution guide
2 |
3 | ## Developing
4 |
5 | All contributions to _react-timing-hooks_ are very welcome!
6 |
7 | Please consider these guidelines when filing a pull request or similar:
8 |
9 | ### Commit message format
10 | All commit messages must adhere to the [conventional commit](https://www.conventionalcommits.org/en/v1.0.0/) format.
11 |
12 | So **please use `npm run commit`** to commit your staged changes.
13 |
14 | ### Testing
15 | Test everything before you commit it: `npm run test` will take care of that.
16 |
17 | If you implement new features, please write tests that cover these new features. We have both unit and integration tests.
18 |
19 | ### Code formatting
20 | Use [prettier](https://prettier.io) while developing. You can check your code with `npm run prettier:check` to make sure everything's formatted correctly.
21 |
22 | ### Code of conduct
23 | Please do also make sure to follow the [code of conduct](#code-of-conduct) in all your interactions with the project.
24 |
25 | ## Creating releases
26 |
27 | react-timing-hooks uses [standard-version](https://github.com/conventional-changelog/standard-version)
28 | to release new versions automatically.
29 |
30 | * Commits of type `fix` will trigger bugfix releases, think `0.0.1`
31 | * Commits of type `feat` will trigger feature releases, think `0.1.0`
32 | * Commits with `BREAKING CHANGE` in body or footer will trigger breaking releases, think `1.0.0`
33 |
34 | **All other commit types will trigger no new release.**
35 |
36 | ## Code of Conduct
37 |
38 | ### Our Pledge
39 |
40 | We as members, contributors, and leaders pledge to make participation in our
41 | community a harassment-free experience for everyone, regardless of age, body
42 | size, visible or invisible disability, ethnicity, sex characteristics, gender
43 | identity and expression, level of experience, education, socio-economic status,
44 | nationality, personal appearance, race, religion, or sexual identity
45 | and orientation.
46 |
47 | We pledge to act and interact in ways that contribute to an open, welcoming,
48 | diverse, inclusive, and healthy community.
49 |
50 | ### Our Standards
51 |
52 | Examples of behavior that contributes to a positive environment for our
53 | community include:
54 |
55 | * Demonstrating empathy and kindness toward other people
56 | * Being respectful of differing opinions, viewpoints, and experiences
57 | * Giving and gracefully accepting constructive feedback
58 | * Accepting responsibility and apologizing to those affected by our mistakes,
59 | and learning from the experience
60 | * Focusing on what is best not just for us as individuals, but for the
61 | overall community
62 |
63 | Examples of unacceptable behavior include:
64 |
65 | * The use of sexualized language or imagery, and sexual attention or
66 | advances of any kind
67 | * Trolling, insulting or derogatory comments, and personal or political attacks
68 | * Public or private harassment
69 | * Publishing others' private information, such as a physical or email
70 | address, without their explicit permission
71 | * Other conduct which could reasonably be considered inappropriate in a
72 | professional setting
73 |
74 | ### Enforcement Responsibilities
75 |
76 | Community leaders are responsible for clarifying and enforcing our standards of
77 | acceptable behavior and will take appropriate and fair corrective action in
78 | response to any behavior that they deem inappropriate, threatening, offensive,
79 | or harmful.
80 |
81 | Community leaders have the right and responsibility to remove, edit, or reject
82 | comments, commits, code, wiki edits, issues, and other contributions that are
83 | not aligned to this Code of Conduct, and will communicate reasons for moderation
84 | decisions when appropriate.
85 |
86 | ### Scope
87 |
88 | This Code of Conduct applies within all community spaces, and also applies when
89 | an individual is officially representing the community in public spaces.
90 | Examples of representing our community include using an official e-mail address,
91 | posting via an official social media account, or acting as an appointed
92 | representative at an online or offline event.
93 |
94 | ### Enforcement
95 |
96 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
97 | reported to the community leaders responsible for enforcement at
98 | [mail@ericlambrecht.de](mail@ericlambrecht.de).
99 | All complaints will be reviewed and investigated promptly and fairly.
100 |
101 | All community leaders are obligated to respect the privacy and security of the
102 | reporter of any incident.
103 |
104 | ### Enforcement Guidelines
105 |
106 | Community leaders will follow these Community Impact Guidelines in determining
107 | the consequences for any action they deem in violation of this Code of Conduct:
108 |
109 | #### 1. Correction
110 |
111 | **Community Impact**: Use of inappropriate language or other behavior deemed
112 | unprofessional or unwelcome in the community.
113 |
114 | **Consequence**: A private, written warning from community leaders, providing
115 | clarity around the nature of the violation and an explanation of why the
116 | behavior was inappropriate. A public apology may be requested.
117 |
118 | #### 2. Warning
119 |
120 | **Community Impact**: A violation through a single incident or series
121 | of actions.
122 |
123 | **Consequence**: A warning with consequences for continued behavior. No
124 | interaction with the people involved, including unsolicited interaction with
125 | those enforcing the Code of Conduct, for a specified period of time. This
126 | includes avoiding interactions in community spaces as well as external channels
127 | like social media. Violating these terms may lead to a temporary or
128 | permanent ban.
129 |
130 | #### 3. Temporary Ban
131 |
132 | **Community Impact**: A serious violation of community standards, including
133 | sustained inappropriate behavior.
134 |
135 | **Consequence**: A temporary ban from any sort of interaction or public
136 | communication with the community for a specified period of time. No public or
137 | private interaction with the people involved, including unsolicited interaction
138 | with those enforcing the Code of Conduct, is allowed during this period.
139 | Violating these terms may lead to a permanent ban.
140 |
141 | #### 4. Permanent Ban
142 |
143 | **Community Impact**: Demonstrating a pattern of violation of community
144 | standards, including sustained inappropriate behavior, harassment of an
145 | individual, or aggression toward or disparagement of classes of individuals.
146 |
147 | **Consequence**: A permanent ban from any sort of public interaction within
148 | the community.
149 |
150 | ### Attribution
151 |
152 | This Code of Conduct is adapted from the [Contributor Covenant][homepage],
153 | version 2.0, available at
154 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
155 |
156 | Community Impact Guidelines were inspired by [Mozilla's code of conduct
157 | enforcement ladder](https://github.com/mozilla/diversity).
158 |
159 | [homepage]: https://www.contributor-covenant.org
160 |
161 | For answers to common questions about this code of conduct, see the FAQ at
162 | https://www.contributor-covenant.org/faq. Translations are available at
163 | https://www.contributor-covenant.org/translations.
164 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Eric Lambrecht
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/docs/_assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "{{ site.theme }}";
5 |
6 | .main-content {
7 | p {
8 | font-size: 1rem;
9 | }
10 |
11 | ul,ol {
12 | font-size: 1rem;
13 | }
14 |
15 | h4+ul, h4+ol {
16 | font-size: 0.9rem;
17 |
18 | code {
19 | font-size: 0.8rem;
20 | }
21 |
22 | li:not(:first-child) {
23 | margin-top: 4px;
24 | }
25 | }
26 |
27 | h4 > code {
28 | font-size: 1rem;
29 | font-weight: 700;
30 | position: relative;
31 |
32 | &::before {
33 | content: '';
34 | display: inline-block;
35 | position: absolute;
36 | left: -26px;
37 | top: 10px;
38 | background: #dce6f0;
39 | height: 3px;
40 | width: 13px;
41 | }
42 | }
43 | }
44 |
45 | @media screen and (max-width: 64em) and (min-width: 42em) {
46 | .main-content {
47 | p {
48 | font-size: 1rem;
49 | }
50 | }
51 | }
52 |
53 | @media (min-width: 31.25rem) {
54 | .site-title.site-title {
55 | font-size: 1.4rem !important;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | remote_theme: just-the-docs/just-the-docs
2 | title: React Timing Hooks
3 | description: API documentation for react-timing-hooks
4 | tagline: API documentation for react-timing-hooks
5 | search_enabled: true
6 | callouts:
7 | note:
8 | title: Note
9 | color: purple
10 | warning:
11 | title: Warning
12 | color: yellow
13 | danger:
14 | title: Danger
15 | color: red
16 | highlight:
17 | color: blue
18 | # Aux links for the upper right navigation
19 | aux_links:
20 | "React Timing Hooks on GitHub":
21 | - "https://github.com/EricLambrecht/react-timing-hooks"
22 |
23 |
--------------------------------------------------------------------------------
/docs/boilerplate.md:
--------------------------------------------------------------------------------
1 | ---
2 | nav_exclude: true
3 | ---
4 |
5 | ---
6 | title: title
7 | parent: parent
8 | nav_order: 1
9 | ---
10 |
11 | #useClock
12 |
13 | This hook can be used to render a clock, i.e. a time-string that updates every second.
14 |
15 | # title
16 |
17 | ## Example
18 |
19 | ## API
20 |
21 | ### Params
22 |
23 | `signature()`
24 |
25 | | Name | Description |
26 | |:-----------------|:---------------------------------------------------------------------|
27 | | callback | bla |
28 | | timeout | the timeout in milliseconds |
29 |
30 | ### Return value
31 |
32 | This hooks has no return value.
33 |
34 |
35 | ## param list with defaults
36 |
37 | | Name | Default | Description |
38 | |:-------------|:------------------|:---------------------------------------------------------------------|
39 | | callback | `undefined` | a function that will be invoked as soon as the timeout expires |
40 | | timeout | `undefined` | the timeout in milliseconds |
41 |
42 |
43 | ## param list without defaults
44 |
45 | | Name | Description |
46 | |:-----------------|:---------------------------------------------------------------------|
47 | | callback | a function that will be invoked as soon as the timeout expires |
48 | | timeout | the timeout in milliseconds |
49 |
--------------------------------------------------------------------------------
/docs/callbacks/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Callbacks / Functions
4 | description: React hooks to create timed callbacks
5 | nav_order: 3
6 | has_children: true
7 | ---
8 |
9 | # Timeouts
10 |
11 | React hooks that return some form of timed callback.
12 | {: .fs-6 .fw-300 }
13 |
14 | Most of these callbacks are based on [setTimeout()][timeout-mdn].
15 |
16 | For *rate-limiting* use `useThrottle()` or `useDebounce()`. For *pure timeouts* use `useTimeout()` or `useTimeoutEffect()`.
17 |
18 | {: .note }
19 | All of these hooks are memoized and will automatically take care of clearing any pending timeouts on unmount.
20 |
21 | [timeout-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
22 |
--------------------------------------------------------------------------------
/docs/callbacks/useAnimationFrame.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useAnimationFrame
3 | description: A React hook that wraps window.requestAnimationFrame()
4 | parent: Callbacks / Functions
5 | nav_order: 5
6 | ---
7 |
8 | # useAnimationFrame
9 |
10 | Use this hook to create a callback that executes the provided function via [`window.requestAnimationFrame()`][raf-mdn].
11 |
12 | {: .warning }
13 | _This hook is quite low level._ You might want to use `useAnimationFrameLoop()` or `useIdleCallback()` instead.
14 |
15 | #### Alternatives
16 |
17 | - [useAnimationFrameLoop()](/react-timing-hooks/loops-and-intervals/useAnimationFrameLoop.html)
18 | - [useIdleCallback()](/react-timing-hooks/callbacks/useIdleCallback.html)
19 | - [useTimeout()](/react-timing-hooks/callbacks/useTimeout.html)
20 |
21 | ## Example
22 |
23 | ```javascript
24 | import { useAnimationFrame } from 'react-timing-hooks'
25 |
26 | const myFunc = () => console.log("hi")
27 | const runMyFuncOnAnimationFrame = useAnimationFrame(myFunc)
28 |
29 | return
30 | ```
31 |
32 | ## API
33 |
34 | `useAnimationFrame(callback)`
35 | {: .fs-5 .fw-300 }
36 |
37 | ### Params
38 |
39 | | Name | Description |
40 | |:-----------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
41 | | callback | A function that will be called at the next available animation frame. See [requestAnimationFrame()](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) |
42 |
43 | ### Return value
44 |
45 | A function. If you call this function, your `callback` will be queued and executed at the next available animation frame.
46 |
47 | ## Notes
48 |
49 | Queued animation frame callbacks will be automatically canceled on unmount.
50 |
51 | [raf-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
52 |
--------------------------------------------------------------------------------
/docs/callbacks/useDebounce.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useDebounce
3 | description: A React hook to created debounced callbacks
4 | parent: Callbacks / Functions
5 | nav_order: 3
6 | ---
7 |
8 | # useDebounce
9 |
10 | Debounces a callback.
11 | {: .fs-6 .fw-300 }
12 |
13 | Use this hook if you want a function that "blocks" consecutive calls until a specified
14 | time has passed since the last invocation. This is called **debouncing**.
15 |
16 | {: .note-title }
17 | > Throttle vs. Debounce
18 | >
19 | > If you want a callback that [doesn't debounce but throttles][thr-vs-deb], take a look at `useThrottle()`.
20 |
21 | If you want a non-debouncing and non-throttling version, take a look at `useTimeout()`.
22 |
23 | Pending timeouts will also be cleared in case the component unmounts.
24 |
25 | #### Alternatives
26 | - For throttling: [useThrottle()](/react-timing-hooks/callbacks/useThrottle.html).
27 | - For callbacks that execute when the browser is idle: [useIdleCallback()](/react-timing-hooks/callbacks/useIdleCallback.html).
28 |
29 | ## Example
30 |
31 | ```javascript
32 | import { useDebounce } from 'react-timing-hooks'
33 |
34 | // Debounce key up event, message will be logged if last key up event has been more than 2 seconds ago.
35 | const onKeyUp = useDebounce(() => console.log('key up'), 2000)
36 |
37 | return
38 | ```
39 |
40 | ## API
41 |
42 | `useDebounce(callback, waitMs, options)`
43 | {: .fs-5 .fw-300 }
44 |
45 | ### Params
46 |
47 | | Name | Default | Description |
48 | |:-----------------|-------------|:------------------------------------------------------------------------|
49 | | callback | _*required_ | A function that will be invoked as soon as the timeout expires |
50 | | waitMs | _*required_ | The minimum waiting time until an invocation can happen. |
51 | | options | `{}` | Debouncing options |
52 | | options.leading | `false` | If `true` the callback will be invoked immediately / before the timeout |
53 | | options.trailing | `true` | If `true` the callback will be invoked after the timeout |
54 |
55 |
56 | ### Return value
57 |
58 | A function will be returned, that - once executed - will run the `callback`-function after `{timeout}` milliseconds.
59 | The function will also return the timeout id in case you want to clear it manually via `clearTimeout(id)`.
60 |
61 | ## Notes
62 |
63 | This hook will automatically clear any pending timeout on unmount. Timeout's can be cleared manually as well (see "Return value").
64 |
65 | [thr-vs-deb]: https://css-tricks.com/the-difference-between-throttling-and-debouncing/
66 |
--------------------------------------------------------------------------------
/docs/callbacks/useIdleCallback.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useIdleCallback
3 | description: A React hook that wraps window.requestIdleCallback()
4 | parent: Callbacks / Functions
5 | nav_order: 4
6 | ---
7 |
8 | # useIdleCallback
9 |
10 | Use this hook if you want to delay the execution of a function to a time **when the browser is idle**.
11 |
12 | A good use-case for this might be _user tracking_, for instance.
13 |
14 | {: .important }
15 | See [requestIdleCallback()](https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback) to learn
16 | more about the concept of "idle callbacks".
17 |
18 | ## Example
19 |
20 | ```javascript
21 | import { useIdleCallback } from 'react-timing-hooks'
22 |
23 | // Track button click when idle
24 | const trackClickWhenIdle = useIdleCallback(trackClick)
25 |
26 | return
27 | ```
28 |
29 | ## API
30 |
31 | `useIdleCallback(callback, options)`
32 | {: .fs-5 .fw-300 }
33 |
34 | ### Params
35 |
36 | | Name | Default value | Description |
37 | |:-----------------|:--------------------|:--------------------------------------------------------|
38 | | callback | _This is required._ | Callback that will be invoked when the browser is idle. |
39 | | options | `undefined` | options for `requestIdleCallback`. |
40 |
41 | ### Return value
42 |
43 | A function that executes your callback as an idle callback.
44 |
45 | ## Notes
46 |
47 | Any registered idle callbacks will be canceled on unmount.
48 |
49 | {: .warning }
50 | This hook **will print a console warning** if the browser doesn't support `requestIdleCallback`.
51 |
--------------------------------------------------------------------------------
/docs/callbacks/useThrottle.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useThrottle
3 | description: A React hook to created throttled callbacks
4 | parent: Callbacks / Functions
5 | nav_order: 2
6 | ---
7 |
8 | # useThrottle
9 |
10 | Throttles a callback.
11 | {: .fs-6 .fw-300 }
12 |
13 | Can be used for **rate-limiting** – the callback will only be invoked every X milliseconds (X being the set timeout),
14 | even if it was called more frequently.
15 |
16 | {: .note-title }
17 | > Throttle vs. Debounce
18 | >
19 | > Similar, [but different(!)][thr-vs-deb], is the `useDebounce()` hook, which blocks the invocation entirely until the function was
20 | > stopped being called for X milliseconds.
21 |
22 | By default, the throttled function will always be called immediately (`options.leading` is true by default) and then
23 | (`options.trailing` is true by default) also after every X milliseconds for consecutive calls.
24 |
25 | #### Alternatives
26 |
27 | - If you want to throttle the state updates, you can use [useThrottledState()](/react-timing-hooks/state/useThrottledState.html).
28 | - If you want to debounce: [useDebounce()](/react-timing-hooks/callbacks/useDebounce.html).
29 |
30 | ## Example
31 |
32 | ```javascript
33 | import { useThrottle } from 'react-timing-hooks'
34 |
35 | // Throttle button click: message can only be logged once every 2 seconds, regardless of how often the button is clicked.
36 | const onClick = useThrottle(() => console.log('clicked'), 2000)
37 |
38 | return
39 | ```
40 |
41 | ## API
42 |
43 | `useThrottle(callback, waitMs, options)`
44 | {: .fs-5 .fw-300 }
45 |
46 | ### Params
47 |
48 | | Name | Default | Description |
49 | |:-----------------|-------------|:------------------------------------------------------------|
50 | | callback | _*required_ | A function that will be invoked as the throttling allows |
51 | | waitMs | _*required_ | Minimum waiting time between consecutive calls |
52 | | options | `{}` | Throttling options |
53 | | options.leading | `true` | If true, invoke the callback immediately/before the timeout |
54 | | options.trailing | `true` | If true, queue invocations for after the timeout |
55 |
56 |
57 | ### Return value
58 |
59 | A function will be returned, that can run the `callback`-function only every `{timeout}` milliseconds.
60 | The function will also return the timeout id in case you want to clear it manually via `clearTimeout(id)`.
61 |
62 | ## Notes
63 |
64 | This hook will automatically clear any pending timeout on unmount. Timeout's can be cleared manually as well (see "Return value").
65 |
66 | [thr-vs-deb]: https://css-tricks.com/the-difference-between-throttling-and-debouncing/
67 |
--------------------------------------------------------------------------------
/docs/callbacks/useTimeout.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useTimeout
3 | description: A React hook tp wrap setTimeout()
4 | parent: Callbacks / Functions
5 | nav_order: 1
6 | ---
7 |
8 | # useTimeout
9 |
10 | A react wrapper for [setTimeout](https://developer.mozilla.org/en-US/docs/Web/API/setTimeout) – no leaks on unmount!
11 | {: .fs-6 .fw-300 }
12 |
13 | Use this hook if you want a function that executes the provided callback after the specified amount of time.
14 |
15 | This **will not debounce or throttle** the callbacks, i.e. consecutive calls of this function will all spawn
16 | new timeouts even if some are still pending. If you want a debouncing version, take a look at `useDebounce()`.
17 | If you want a throttling version, see `useThrottle()`.
18 |
19 | {: .note }
20 | Pending timeouts will only(!) be cleared in case the component unmounts. If you want to clear them manually, you can do so via the returned timeout id.
21 |
22 | #### Alternatives
23 |
24 | - If you want to execute a timeout every time a certain value changes, `useTimeoutEffect()` might be better suited.
25 | - For throttling [useThrottle()](/react-timing-hooks/callbacks/useThrottle.html).
26 | - For debouncing [useThrottle()](/react-timing-hooks/callbacks/useThrottle.html).
27 |
28 | ## Example
29 |
30 | ```javascript
31 | import { useTimeout } from 'react-timing-hooks'
32 |
33 | // Hide something after 2 seconds
34 | const hideDelayed = useTimeout(() => setHide(true), 2000)
35 |
36 | return
37 | ```
38 |
39 | ## API
40 |
41 | `useTimeout(callback, timeout)`
42 | {: .fs-5 .fw-300 }
43 |
44 | ### Params
45 |
46 | | Name | Description |
47 | |:---------|:---------------------------------------------------------------|
48 | | callback | a function that will be invoked as soon as the timeout expires |
49 | | timeout | the timeout in milliseconds |
50 |
51 | ### Return value
52 |
53 | A function will be returned, that - once executed - will run the `callback`-function after `{timeout}` milliseconds.
54 | The function will also return the timeout id in case you want to clear it manually via `clearTimeout(id)`.
55 |
56 | ## Notes
57 |
58 | This hook will automatically clear any pending timeout on unmount. Timeout's can be cleared manually as well (see "Return value").
59 |
--------------------------------------------------------------------------------
/docs/effects/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Effects
4 | nav_order: 4
5 | has_children: true
6 | ---
7 |
8 | # Effects
9 |
10 | React hooks that are based on `useEffect()`.
11 | {: .fs-6 .fw-300 }
12 |
13 | These hooks behave like a regular `useEffect` except that you gain access to timeouts etc. in your effect callback.
14 | These timeouts (or idle callbacks) will be managed by react-timing-hooks, i.e. they will also be cleaned up properly.
15 |
16 | [idle-cb-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
17 |
--------------------------------------------------------------------------------
/docs/effects/useIdleCallbackEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useIdleCallbackEffect
3 | description: A React hook to create a useEffect with idle callbacks
4 | parent: Effects
5 | nav_order: 2
6 | ---
7 |
8 | # useIdleCallbackEffect
9 |
10 | This works like a regular `useEffect()` hook, except that it adds an enhanced version of [`window.requestIdleCallback()`][mdn]
11 | to the callback args.
12 |
13 | There might be cases where the simpler `useIdleCallback()` hook might be more suitable.
14 |
15 | {: .note }
16 | Pending registered idle callbacks will be canceled on unmount.
17 |
18 | ## Example
19 |
20 | ```javascript
21 | import { useIdleCallbackEffect } from 'react-timing-hooks'
22 |
23 | // Track page view (when browser is idle) whenever "page" changes
24 | useIdleCallbackEffect(onIdle => {
25 | if (page) {
26 | onIdle(() => trackPageView(page))
27 | }
28 | }, [page])
29 | ```
30 |
31 | ## API
32 |
33 | `useIdleCallbackEffect(effectCallback, deps)`
34 | {: .fs-5 .fw-300 }
35 |
36 | ### Params
37 |
38 | | Name | Description |
39 | |:-----------------|:------------------------------------------------------------------------------------------------------|
40 | | effectCallback | Works like a `useEffect` callback, but receives one argument, instead of none. See below for details. |
41 | | deps | Your regular `useEffect` dependency array. |
42 |
43 | ##### effectCallback(requestIdleCallback)
44 |
45 | The effect callback receives one argument:
46 |
47 | 1. `requestIdleCallback(cb, opts)` – the signature of this function is identical to [`window.requestIdleCallback()`][mdn]
48 | The only difference is, that created idle callback requests (created with this function) will be automatically cancelled on unmount if still pending while unmounting.
49 |
50 | ### Return value
51 |
52 | This hook has no return value.
53 |
54 | ## Notes
55 |
56 | Any registered idle callbacks will be canceled on unmount.
57 |
58 | {: .warning }
59 | This hook **will print a console warning** if the browser doesn't support `requestIdleCallback`.
60 |
61 | [mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
62 |
--------------------------------------------------------------------------------
/docs/effects/useTimeoutEffect.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useTimeoutEffect
3 | description: A React hook to create a useEffect with timeout
4 | parent: Effects
5 | nav_order: 1
6 | ---
7 |
8 | # useTimeoutEffect
9 |
10 | This works like a regular `useEffect` hook, except that it adds a `setTimeout` like function
11 | to the callback args. This way, one our multiple timeouts can be triggered every time state or props of your component change.
12 |
13 | If you want to just fire a simple function call after a specific delay, you might want to use `useTimeout()` instead.
14 |
15 | {: .note }
16 | Pending timeouts will be automatically cleared on unmount.
17 |
18 | ## Example
19 |
20 | ```javascript
21 | import { useTimeoutEffect } from 'react-timing-hooks'
22 |
23 | // Delay the transition of a color by one second everytime it changes
24 | useTimeoutEffect((timeout, clear) => {
25 | if (color) {
26 | timeout(() => transitionTo(color), 1000)
27 | }
28 | }, [color])
29 | ```
30 |
31 | ## API
32 |
33 | `useTimeoutEffect(effectCallback, timeout)`
34 | {: .fs-5 .fw-300 }
35 |
36 | ### Params
37 |
38 | | name | description |
39 | |:---------------|:---------------------------------------------------------------------|
40 | | effectCallback | Like a regular `useEffect` callback, but receives it receives two arguments, see below |
41 | | timeout | This is your regular `useEffect` dependency array. Returns timeout `id`. |
42 |
43 | ##### effectCallback(timeout, clear)
44 |
45 | The effect callback receives two arguments:
46 |
47 | 1. `timeout(cb, timeout)`: This has the same signature as a native `setTimeout`. The only difference is, that timeouts created with this function will automatically be cleared when you unmount the component.
48 | 2. `clear`: A function to manually clear all spawned timeouts if that is desired. (Timeouts will be cleared automatically on unmount).
49 |
50 |
51 | ## Notes
52 |
53 | This hook will automatically clear any pending timeout(s) on unmount. You don't have to clean up the timeouts manually.
54 | However, you can clear them manually via the returned id (or all at once using the second param of the effect callback).
55 |
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Quick Start
4 | nav_order: 1
5 | has_children: false
6 | ---
7 |
8 |
9 |
10 | # Quick Start
11 | This is the documentation of react-timing-hooks.
12 | {: .fs-6 .fw-300 }
13 |
14 | [List of hooks](/react-timing-hooks/list-of-all-hooks/){: .btn .btn-primary .fs-5 .mb-4 .mb-md-0 .mr-2 }
15 | [View it on GitHub][repo]{: .btn .fs-5 .mb-4 .mb-md-0 }
16 |
17 | ---
18 |
19 | ## Installation
20 |
21 | ```bash
22 | # via npm
23 | npm i react-timing-hooks
24 |
25 | # via yarn
26 | yarn add react-timing-hooks
27 | ```
28 |
29 | {: .note }
30 | Since this is a React package, you have to install React `^16.8.0`, `^17.0.0` or `^18.0.0`, too, in order to use this package.
31 |
32 | ## Getting started
33 |
34 | Simply import the hook you need and use it in your React app! Here is an overview of all hooks in this package: [list of all hooks](/react-timing-hooks/list-of-all-hooks/).
35 |
36 | {: .highlight-title }
37 | > Typescript
38 | >
39 | > This package is developed in Typescript, so **everything is typed out of the box**. You don't need to install types seperately.
40 |
41 | ## Background
42 |
43 | In general all of these hooks are more or less wrappers for standard javascript functions. But since they can be quite
44 | a pain to handle in React components (leaks upon unmount etc.), I wrote this little package.
45 |
46 | There are currently hooks available for:
47 |
48 | * [setTimeout][timeout-mdn] (useTimeout, useTimeoutEffect, useThrottledState, ...)
49 | * [setInterval][interval-mdn] (useInterval, useTimer, useClock, ...)
50 | * [requestAnimationFrame][raf-mdn] (useAnimationFrame, useAnimationFrameLoop)
51 | * [requestIdleCallback][idle-cb-mdn] (useIdleCallback, useIdleCallbackEffect)
52 |
53 | **All hooks are documented on this page** (see sidebar). They should be pretty straight forward to use, but feel free
54 | to add an issue on GitHub if you have any ideas for improvement.
55 |
56 | {: .highlight-title }
57 | > Package size / Treeshaking
58 | >
59 | > This package is extremely small already (see [here](https://bundlephobia.com/result?p=react-timing-hooks)), but your bundle
60 | > size will be even less affected by this package, because it's completely **tree-shakable**, i.e. only hooks you actually use
61 | > will be bundled into your app js.
62 |
63 | ### Preventing leaks on unmount
64 |
65 | One of the most cumbersome things when dealing with timeouts and intervals in React is the **boilerplate** you have to write in order to use them properly.
66 |
67 | What you what normally do is to write clean-up code to manually clear pending timeouts/intervals in your React components.
68 | **With React Timing Hooks you don't have to do that.**
69 |
70 | #### Example
71 |
72 | For example: You might have a timeout that runs under a certain condition. In this case a cleanup
73 | has to be done in a separate `useEffect` call that cleans everything up (but only on unmount).
74 |
75 | Your code could look like this:
76 |
77 | ```javascript
78 | import { useEffect } from 'react'
79 |
80 | const TimeoutRenderer = ({ depA, depB }) => {
81 | const [output, setOutput] = useState(null)
82 | const timeoutId = useRef(null)
83 |
84 | useEffect(() => {
85 | if (depA && depB) {
86 | timeoutId.current = setTimeout(() => setOutput('Hello World'), 1000)
87 | }
88 | }, [depA, depB])
89 |
90 | useEffect(() => {
91 | return function onUnmount() {
92 | if (timeoutId.current !== null) {
93 | clearTimeout(timeoutId.current)
94 | }
95 | }
96 | }, [timeoutId])
97 |
98 | return output ? (
99 |
121 | ) : null
122 | }
123 | ```
124 |
125 | In this case `react-timing-hooks` automatically took care of cleaning up the timeout for you (if the component is mounted for less than a second for instance).
126 |
127 | ### Memoization
128 |
129 | Memoization is important if you depend on callbacks in your hook dependency arrays. You **don't have to worry about memoization** of your callbacks (by wrapping stuff in `useCallback` for example). React Timing Hooks is taking care of that for you. So even if you pass a simple inline arrow function to one of these hooks, the return value (if there is one) will not change on every render but instead stay the same (i.e. it will be memoized).
130 |
131 | This means something like this is safe to do:
132 |
133 | ```javascript
134 | const [foo, setFoo] = useState(null)
135 | const onFooChange = useTimeout(() => console.log('foo changed one second ago!'), 1000)
136 |
137 | // the following effect will run only when "foo" changes, just as expected. "onFooChange" is memoized and safe to use in a dependency array.
138 | useEffect(() => {
139 | onFooChange()
140 | }, [foo, onFooChange])
141 | ```
142 |
143 | [interval-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setInterval
144 | [timeout-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
145 | [idle-cb-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
146 | [raf-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
147 | [repo]: https://github.com/EricLambrecht/react-timing-hooks
--------------------------------------------------------------------------------
/docs/list-of-all-hooks/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: List of all hooks
4 | description: An overview of all included React hooks in this package
5 | nav_order: 6
6 | has_children: false
7 | ---
8 |
9 | # A list of all hooks
10 |
11 | In case you wonder where to find them.
12 | {: .fs-6 .fw-300 }
13 |
14 | ## By Javascript function
15 |
16 | #### Set Timeout | [MDN][timeout-mdn]
17 | - [useTimeout](/react-timing-hooks/callbacks/useTimeout.html)
18 | - [useTimeoutEffect](/react-timing-hooks/effects/useTimeoutEffect.html)
19 |
20 | #### Set Interval | [MDN][interval-mdn]
21 | - [useInterval](/react-timing-hooks/loops-and-intervals/useInterval.html)
22 |
23 | #### Request Idle Callback | [MDN][idle-cb-mdn]
24 | - [useIdleCallback](/react-timing-hooks/callbacks/useIdleCallback.html).
25 | - [useIdleCallbackEffect](/react-timing-hooks/effects/useIdleCallbackEffect.html)
26 |
27 | #### Request Animation Frame | [MDN][raf-mdn]
28 | - [useAnimationFrame](/react-timing-hooks/callbacks/useAnimationFrame.html)
29 | - [useAnimationFrameLoop](/react-timing-hooks/loops-and-intervals/useAnimationFrameLoop.html)
30 |
31 | ## By use case
32 |
33 | #### Rate limiting / throttling / debouncing
34 | - [useThrottledState](/react-timing-hooks/state/useThrottledState.html) - tame rapid firing state updates, reducing the number of React updates
35 | - [useThrottle](/react-timing-hooks/callbacks/useThrottle.html)
36 | - [useDebounce](/react-timing-hooks/callbacks/useDebounce.html)
37 |
38 | #### Reactive counters & timers
39 | - [useCounter](/react-timing-hooks/loops-and-intervals/useCounter.html) - a reactive, customizable counter
40 | - [useTimer](/react-timing-hooks/loops-and-intervals/useTimer.html) - a timer
41 | - [useCountdown](/react-timing-hooks/loops-and-intervals/useCountdown.html) - a countdown (ends automatically)
42 |
43 | #### GFX / animation / rendering
44 | - [useAnimationFrameLoop](/react-timing-hooks/loops-and-intervals/useAnimationFrameLoop.html) - for animations, rendering etc.
45 |
46 | #### Time
47 | - [useClock](/react-timing-hooks/loops-and-intervals/useClock.html) - displays a real-time digital clock
48 |
49 | #### Tracking
50 | - [useIdleCallbackEffect](/react-timing-hooks/effects/useIdleCallbackEffect.html)
51 | - [useIdleCallback](/react-timing-hooks/callbacks/useIdleCallback.html)
52 |
53 | #### Oscillation
54 | - [useOscillator](/react-timing-hooks/loops-and-intervals/useOscillator.html)
55 |
56 |
57 | ## By alphabet
58 |
59 | - [useAnimationFrame](/react-timing-hooks/callbacks/useAnimationFrame.html)
60 | - [useAnimationFrameLoop](/react-timing-hooks/loops-and-intervals/useAnimationFrameLoop.html)
61 | - [useClock](/react-timing-hooks/loops-and-intervals/useClock.html)
62 | - [useCountdown](/react-timing-hooks/loops-and-intervals/useCountdown.html)
63 | - [useCounter](/react-timing-hooks/loops-and-intervals/useCounter.html)
64 | - [useDebounce](/react-timing-hooks/callbacks/useDebounce.html)
65 | - [useIdleCallback](/react-timing-hooks/callbacks/useIdleCallback.html).
66 | - [useIdleCallbackEffect](/react-timing-hooks/effects/useIdleCallbackEffect.html)
67 | - [useInterval](/react-timing-hooks/loops-and-intervals/useInterval.html)
68 | - [useOscillator](/react-timing-hooks/loops-and-intervals/useOscillator.html)
69 | - [useThrottle](/react-timing-hooks/callbacks/useThrottle.html)
70 | - [useThrottledState](/react-timing-hooks/state/useThrottledState.html)
71 | - [useTimeout](/react-timing-hooks/callbacks/useTimeout.html)
72 | - [useTimeoutEffect](/react-timing-hooks/effects/useTimeoutEffect.html)
73 | - [useTimer](/react-timing-hooks/loops-and-intervals/useTimer.html)
74 |
75 |
76 | [interval-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setInterval
77 | [timeout-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setTimeout
78 | [idle-cb-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window/requestIdleCallback
79 | [raf-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
80 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Loops & Intervals
4 | description: React hooks for creating loops and intervals
5 | nav_order: 2
6 | has_children: true
7 | ---
8 |
9 | # Loops and Intervals
10 |
11 | React hooks for calling functions at a regular interval.
12 | {: .fs-6 .fw-300 }
13 |
14 | Many of these hooks are built upon [setInterval()][interval-mdn].
15 |
16 | The intervals that these hooks create can be **paused, resumed, stopped and re-started**. Counters can also be **reset**.
17 | Additionally, these hooks will automatically take care of clearing any pending intervals if a component unmounts too early for example.
18 |
19 | {: .note }
20 | Most of these hooks **do not automatically start** on mount, but rather have to be started manually via the returned `start()` function. However, you can start automatically by setting `options.startOnMount = true`.
21 |
22 | [interval-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/setInterval
23 |
24 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useAnimationFrameLoop.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useAnimationFrameLoop
3 | description: A React hook to create a loop based on animation frames
4 | parent: Loops & Intervals
5 | nav_order: 3
6 | ---
7 |
8 | # useAnimationFrameLoop
9 |
10 | Use this hook if you want to execute something (like css updates, or Web GL rendering) in an **animation frame
11 | loop** at **roughly 60FPS** in your React component.
12 |
13 | You can **pause** or **stop** the loop via the returned control callbacks.
14 | Pausing will make the hook still running on an animation frame loop, but without executing your callback.
15 | Stopping will completely halt it and cancel any open animation frame requests, just as if you would unmount it.
16 | If **performance** is important to you, you should stop the loop instead of pausing it whenever possible.
17 |
18 | {: .note }
19 | By default, the loop is _stopped_ on mount and has to be started manually. If you want the loop to start immediately on mount, use `options.startOnMount`.
20 |
21 | The browser will call your function approximately 60 times a second (60 FPS) if the performance of your app allows it.
22 |
23 | {: .important }
24 | See [window.requestAnimationFrame()][raf-mdn] to learn more about the inner workings of "animation frames".
25 |
26 | ## Example
27 |
28 | ```javascript
29 | import { useRef } from 'react'
30 | import { useAnimationFrameLoop } from 'react-timing-hooks'
31 |
32 | const Renderer = () => {
33 | const delta = useRef(0)
34 | const canvasRef = useRef(null)
35 | const canvas = canvasRef.current
36 | const context = canvas.getContext('2d')
37 |
38 | const updateCanvas = (d) => {
39 | context.fillStyle = '#000000'
40 | context.fillRect(d, d, context.canvas.width, context.canvas.height)
41 | }
42 |
43 | const { start, stop, isStopped } = useAnimationFrameLoop(() => {
44 | delta.current += 1
45 | updateCanvas(delta.current)
46 | })
47 |
48 | return <>
49 |
50 |
53 | >
54 | }
55 | ```
56 |
57 | ## API
58 |
59 | `useAnimationFrameLoop(cb, options = {})`
60 | {: .fs-5 .fw-300 }
61 |
62 | ### Params
63 |
64 | | Name | Default | Description |
65 | |:---------------------|:-----------------------------|:-----------------------------------------------------------------------------------------------------------|
66 | | callback | _This argument is required_ | Function that will be called on every (available) animation frame |
67 | | options.startOnMount | `false` | If true, the counter will immediately start on mount. If false, it has to be started manually via start(). |
68 |
69 | ### Return value
70 |
71 | An object of animation frame loop controls:
72 |
73 | | Name | Description |
74 | |:----------|:--------------------------------------------------------------------------------------------------------------------------------|
75 | | isPaused | A boolean that indicates whether the loop is currently paused. |
76 | | isStopped | A boolean that indicates whether the loop is currently stopped. Meaning it cannot be resumed, but only restarted via `start()`. |
77 | | pause | A function that will temporarily pause the loop without destroying it, i.e. it will continue to run without executing the callback. |
78 | | resume | A function that resumes a paused loop. |
79 | | stop | A function that stops and destroys(!) the loop. |
80 | | start | A function that restarts a stopped loop.
81 |
82 | ## Notes
83 |
84 | The loop will be destroyed on unmount.
85 |
86 | [raf-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useClock.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useClock
3 | description: A React hook to show the current time
4 | parent: Loops & Intervals
5 | nav_order: 7
6 | ---
7 |
8 | # useClock
9 |
10 | This hook creates a sort of clock, i.e. a reactive time-based value that updates **every second**.
11 |
12 | The output of useClock is easily customizable via the `options` argument, see [below](#params).
13 |
14 | {: .highlight-title }
15 | > Typescript
16 | >
17 | > `useClock` is also generic (by default `useClock` is used). The generic type has to be specified if a
18 | > custom formatter (see `options.customFormatter`) is used that returns something else than a string.
19 |
20 | ## Example
21 |
22 | ```javascript
23 | import { useClock } from 'react-timing-hooks'
24 |
25 | // this will show a time like 1:13:56 PM that is updated every second. Like a clock.
26 | const [currentTime, { start, stop, ...rest }] = useClock()
27 | return {currentTime}
28 | ```
29 |
30 | ## API
31 |
32 | `useClock(options: ClockOptions): [T, CounterControls]`
33 | {: .fs-5 .fw-300 }
34 |
35 | ### Params
36 |
37 | `Date.toLocaleTimeString` is used to output the time. The output can be formatted via `options.locales` and/or `options.dateTimeFormatOptions`.
38 |
39 | Alternatively, a completely custom formatter can also be used (see `options.customFormatter`).
40 |
41 | | Name | Type | Default | Description |
42 | |:----------------------------------|:-----------------------------|:-------------|:-------------------------------------------------------------------------------------------------------------|
43 | | `options` | `object` | `undefined` | An object of options, see below |
44 | | `options.locales` | `string or string[]` | `undefined` | Locales forwarded to `Date.toLocaleTimeString()`, ignored if custom formatter is used. |
45 | | `options.dateTimeFormatOptions` | `Intl.DateTimeFormatOptions` | `undefined` | Options forwarded to `Date.toLocaleTimeString()`, ignored if custom formatter is used. |
46 | | `options.customFormatter` | `(date: Date) => T` | `undefined` | Alters the return value of `useClock`. Must return `T`. |
47 | | `options.startTimeInMilliseconds` | `number` | `Date.now()` | A number in milliseconds, marking the start time of the clock. |
48 | | `options.keepPausedClockRunningInBackground` | `boolean` | `true` | If true, pausing will only stop the output-update but not the underlying clock, so that it resumes at the correct time if resumed. |
49 |
50 | ### Generic type
51 |
52 | Defaults to `string`. Does have to be set only when a custom formatter is used.
53 |
54 | ### Return value
55 |
56 | An Array with two elements:
57 | - `0`: A formatted time string (by default) or the output of `options.customFormatter` (if set) – updated every second.
58 | - `1`: Controls to pause, resume, start and stop the clock. Use `pause()` if you want the clock to resume at the correct time.
59 |
60 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useCountdown.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useCountdown
3 | description: A React hook to create a reactive countdown
4 | parent: Loops & Intervals
5 | nav_order: 5
6 | ---
7 |
8 | # useCountdown
9 |
10 | 10…, 9…, 8…, 7…
11 | {: .fs-6 .fw-300 }
12 |
13 | Use this hook if you want to create a **countdown**, i.e. a reactive number that is **decremented every second**.
14 | The hook will stop its interval automatically when it reaches the end.
15 |
16 | The event callback **`options.onEnd()`** will be called as soon **as the end value is reached**.
17 |
18 | {: .note }
19 | By default, the countdown is _stopped_ on mount and has to be started manually.
20 | If you want the countdown to start automatically on mount, use `options.startOnMount`.
21 |
22 | This hook is similar to [useTimer()](/react-timing-hooks/loops-and-intervals/useTimer.html) which counts _up_ every second, but does not have an end value.
23 | If you need a countdown that counts *upwards*, you can use `options.stepSize` and change it to `1` or higher.
24 |
25 | #### Alternatives
26 |
27 | For a more freedom/versatility, you can use [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html).
28 |
29 | ## Example
30 |
31 | ```javascript
32 | import { useCountdown } from 'react-timing-hooks'
33 |
34 | // this will count from 10 to 0 (updated every second) and stop there
35 | const [counter] = useCountdown(10, 0, {
36 | onEnd: () => console.log('BOOM!')
37 | })
38 |
39 | return {counter}
40 | ```
41 |
42 | ## API
43 |
44 | `useCountdown(start = 0, settings = {})`
45 | {: .fs-5 .fw-300 }
46 |
47 | ### Params
48 |
49 | | Name | Default | Description |
50 | |:----------------------|:--------------|:-------------------------------------------------------------------------------------------------------------|
51 | | start | _is required_ | The initial value of the countdown |
52 | | settings.startOnMount | `false` | If true, the counter will immediately start on mount. If false, it has to be started manually via `start()`. |
53 | | settings.resetOnStop | `false` | If true, the counter will reset to it's starting value on stop/reaching it's end. If false, it won't. |
54 |
55 |
56 |
57 | ### Return value
58 |
59 | An array of format `[countdownValue, counterControls]`, the first value is the current countdown value.
60 |
61 | The second value is an object of counter controls (start, stop, pause, etc.), see [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html#return-value).
62 |
63 | ## Note
64 |
65 | This is essentially a counter (`useCounter`) with `settings.stepSize` set to `1` and `interval` set to `1000`.
66 | Use `useCounter` if you want a more customized timer.
67 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useCounter.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useCounter
3 | description: A React hook to create a reactive counter
4 | parent: Loops & Intervals
5 | nav_order: 2
6 | ---
7 |
8 | # useCounter
9 |
10 | Use this hook if you want to have a **customizable counter** that changes a value by a
11 | certain amount (`settings.stepSize`) every x milliseconds (`settings.interval`).
12 | A start value (`settings.start`) can also be defined.
13 |
14 | {: .note }
15 | By default, the counter is _stopped_ on mount and has to be started manually.
16 | If you want the counter to start automatically on mount, use `settings.startOnMount`.
17 |
18 | {: .note }
19 | Stopping the counter will also **reset the counter** to it's initial start-value per default.
20 | However, this can be changed via `settings.resetOnStop`. You can manually reset it via the returned
21 | `reset()` control-function.
22 |
23 | #### Alternatives
24 |
25 | - If you want a counter that counts up by 1 every second, you can use the
26 | [useTimer()](/react-timing-hooks/loops-and-intervals/useTimer.html) hook.
27 |
28 | - If you want a counter that starts at a certain number and stops at another, use
29 | [useCountdown()](/react-timing-hooks/loops-and-intervals/useCountdown.html).
30 |
31 | ## Example
32 |
33 | ### A regular timer that counts up every second (default)
34 |
35 | ```javascript
36 | import { useCounter } from 'react-timing-hooks'
37 |
38 | // this will count upwards every second
39 | const [counter] = useCounter({
40 | start: 0,
41 | interval: 1000,
42 | stepSize: 1,
43 | startOnMount: true
44 | })
45 |
46 | return {counter}
47 | ```
48 |
49 | ## API
50 |
51 | `useCounter(settings)`
52 | {: .fs-5 .fw-300 }
53 |
54 | ### Params
55 |
56 | | Name | Default | Description |
57 | |:--------------------------------|:--------|:-------------------------------------------------------------------------------------------------------------|
58 | | settings.start | `0` | The initial value of the counter |
59 | | settings.interval | `1000` | The duration between each counter step |
60 | | settings.stepSize | `1` | The amount that is added after each counter step |
61 | | settings.startOnMount | `false` | If true, the counter will immediately start on mount. If false, it has to be started manually via `start()`. |
62 | | settings.resetOnStop | `true` | If true, the counter will reset to the start value on stop. If false, it won't. |
63 | | settings.destroyIntervalOnPause | `true` | If false, the interval is kept running without doing anything until resumed. |
64 |
65 |
66 | ### Return value
67 |
68 | An Array of `[counterValue, counterControls]`.
69 |
70 | The first array item is the current counter value (starting at `settings.start`). This will change every `settings.interval` ms by `settings.stepSize`.
71 |
72 | The second value is an object of counter controls:
73 |
74 | | Name | Description |
75 | |:----------|:------------------------------------------------------------------------------------------------------------------------------------------|
76 | | isPaused | A boolean that indicates whether the counter is currently paused |
77 | | isStopped | A boolean that indicates whether the counter is currently stopped. Meaning it cannot be resumed, but only restarted via `start()`. |
78 | | pause | A function that will temporarily pause the counter. If `settings.destroyIntervalOnPause` is true it will destroy the underlying interval. |
79 | | resume | A function that resumes a paused counter. |
80 | | stop | A function that stops the underlying interval. If `settings.resetOnStop` is true, this will reset the counter. |
81 | | start | A function that start's the counter. |
82 | | reset | A function that resets the counter to it's starting value. |
83 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useInterval.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useInterval
3 | description: A React hook to create a reactive interval . A wrapper for setInterval.
4 | parent: Loops & Intervals
5 | nav_order: 1
6 | ---
7 |
8 | # useInterval
9 |
10 | A react wrapper for [setInterval](https://developer.mozilla.org/en-US/docs/Web/API/setInterval) – no leaks on unmount!
11 | {: .fs-6 .fw-300 }
12 |
13 | This hook allows you to do certain actions at a regular interval, a.k.a. *loops*.
14 | It is a React-wrapper for the native Javascript function [`setInterval`](https://developer.mozilla.org/en-US/docs/Web/API/setInterval).
15 |
16 | In addition to the standard Javascript API, the returned callbacks allow you to **pause, resume, stop and start** the interval, too.
17 |
18 | {: .note }
19 | By default, the interval is _stopped_ on mount and has to be started manually. If you want the interval to start automatically on mount, use `options.startOnMount`.
20 |
21 | {: .highlight-title }
22 | > Good to know
23 | >
24 | > By default, `setInterval` waits one entire interval step to fire its callback for the first time. However, `useInterval()`
25 | > supports an `isLeading` option to invoke the provided callback immediately upon start.
26 |
27 | #### Alternatives
28 |
29 | - If you want to loop very fast – maybe because you want to animate something –
30 | you might want to use [useAnimationFrameLoop()](/react-timing-hooks/loops-and-intervals/useAnimationFrameLoop.html) instead which yields better performance in these cases.
31 |
32 | - If you only want to increase or decrease a numeric value in a regular interval,
33 | take a look at [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html).
34 |
35 |
36 | ## Examples
37 |
38 | ### Simple interval that starts immediately on mount
39 |
40 | ```javascript
41 | import { useInterval } from 'react-timing-hooks'
42 |
43 | // Increase count every 200 milliseconds
44 | const [count, setCount] = useState(0)
45 | const increaseCount = () => setCount(count + 1)
46 | useInterval(increaseCount, 200, { startOnMount: true })
47 | ```
48 |
49 | ### Pausing and resuming an interval
50 |
51 | ```javascript
52 | import { useInterval } from 'react-timing-hooks'
53 |
54 | const [count, setCount] = useState(0)
55 | const increaseCount = () => setCount(count + 1)
56 | const {
57 | start,
58 | pause,
59 | resume,
60 | isPaused
61 | } = useInterval(increaseCount, 200)
62 |
63 | return
64 |
65 |
68 |
69 | ```
70 |
71 | ## API
72 |
73 | `useInterval(callback, delay, options = {})`
74 | {: .fs-5 .fw-300 }
75 |
76 | ### Params
77 |
78 | | Name | Default | Description |
79 | |:---------------------|---------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
80 | | callback | _is required_ | A function that will be invoked as soon as the timeout expires |
81 | | delay | _is required_ | A number (milliseconds) or null. If numeric, it is the delay between each execution of `callback`. See [setInterval()](https://developer.mozilla.org/en-US/docs/Web/API/setInterval). If set to `null`, the interval will stop. |
82 | | options.startOnMount | `false` | If true, the counter will immediately start on mount. If false, it has to be started manually via `start()`. |
83 | | options.isLeading | `false` | If true, the provided callback will be invoked immediately on start. If false (default), the callback's first invocation will be after the first interval step, same behaviour as Javascript's `setInterval`. |
84 |
85 | ### Return value
86 |
87 | An object of interval controls:
88 |
89 | | Name | Description |
90 | |:----------|:------------------------------------------------------------------------------------------------------------------------------------|
91 | | isPaused | A boolean that indicates whether the interval is currently paused. |
92 | | isStopped | A boolean that indicates whether the interval is currently stopped. Meaning it cannot be resumed, but only restarted via `start()`. |
93 | | pause | A function that will temporarily pause the interval without destroying it, i.e. it will continue to run without executing the callback. |
94 | | resume | A function that resumes a paused interval. |
95 | | stop | A function that stops and destroys(!) the interval. |
96 | | start | A function that restarts a stopped interval. |
97 |
98 |
99 | ## Notes
100 |
101 | Pending intervals will be cleared upon unmount.
102 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useOscillator.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useOscillator
3 | description: A React hook to create a oscillating boolean value.
4 | parent: Loops & Intervals
5 | nav_order: 6
6 | ---
7 |
8 | # useOscillator
9 |
10 | Use this hook if you want to have a **customizable oscillator** that toggles a boolean value
11 | every x milliseconds (`settings.interval`). The initial value (`settings.initialValue`) must be defined by the user.
12 |
13 | {: .note }
14 | By default, the oscillator is _stopped_ on mount and has to be started manually.
15 | If you want the oscillator to start automatically on mount, use `settings.startOnMount`.
16 |
17 | {: .note }
18 | Stopping the oscillator will also **reset the boolean value** to it's initial value by default.
19 | However, this can be changed via `settings.resetOnStop`. You can manually reset it via the returned
20 | `reset()` control-function.
21 |
22 | #### Alternatives
23 |
24 | - If you want a counter increments a number instead of toggling a boolean, take a look at the
25 | [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html) hook.
26 |
27 | ## Example
28 |
29 | ### A oscillator timer that toggles between on and off every second
30 |
31 | ```javascript
32 | import { useOscillator } from 'react-timing-hooks'
33 |
34 | const [isOn] = useOscillator({
35 | start: false,
36 | interval: 1000,
37 | startOnMount: true
38 | })
39 |
40 | return {isOn ? 'ON' : 'OFF'}
41 | ```
42 |
43 | ## API
44 |
45 | `useOscillator(settings)`
46 | {: .fs-5 .fw-300 }
47 |
48 | ### Params
49 |
50 | | Name | Default | Description |
51 | |:--------------------------------|:--------|:----------------------------------------------------------------------------------------------------------------|
52 | | settings.initialValue | - | The initial value of the oscillator, i.e. `true` or `false` |
53 | | settings.interval | `1000` | The duration between each oscillator step |
54 | | settings.startOnMount | `false` | If true, the oscillator will immediately start on mount. If false, it has to be started manually via `start()`. |
55 | | settings.resetOnStop | `true` | If true, the oscillator will reset to the start value on stop. If false, it won't. |
56 | | settings.destroyIntervalOnPause | `true` | If false, the interval is kept running in the background without doing anything until resumed. |
57 |
58 |
59 | ### Return value
60 |
61 | An Array of `[value, oscillatorControls]`.
62 |
63 | The first array item is the current oscillator value (starting at `settings.initialValue`). It will toggle every `settings.interval` ms.
64 |
65 | The second value is an object of oscillator controls:
66 |
67 | | Name | Description |
68 | |:----------|:---------------------------------------------------------------------------------------------------------------------------------------------|
69 | | isPaused | A boolean that indicates whether the oscillator is currently paused |
70 | | isStopped | A boolean that indicates whether the oscillator is currently stopped. Meaning it cannot be resumed, but only restarted via `start()`. |
71 | | pause | A function that will temporarily pause the oscillator. If `settings.destroyIntervalOnPause` is true it will destroy the underlying interval. |
72 | | resume | A function that resumes a paused oscillator. |
73 | | stop | A function that stops the underlying interval. If `settings.resetOnStop` is true, this will reset the oscillator. |
74 | | start | A function that start's the oscillator. |
75 | | reset | A function that resets the oscillator to it's initial value. |
76 |
--------------------------------------------------------------------------------
/docs/loops-and-intervals/useTimer.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useTimer
3 | description: A React hook to create a reactive timer. Runs every second.
4 | parent: Loops & Intervals
5 | nav_order: 4
6 | ---
7 |
8 | # useTimer
9 |
10 | Use this hook if you want to create a timer, i.e. a reactive number that is **incremented every second**.
11 |
12 | {: .note }
13 | By default, the timer is _stopped_ on mount and has to be started manually. If you want the timer to start immediately on mount, use `settings.startOnMount`.
14 |
15 | {: .note }
16 | Stopping the timer will also reset the timer to it's initial value per default. However, this can be changed via `settings.resetOnStop`. You can manually reset it via the returned `reset()` control-function.
17 |
18 |
19 | #### Alternatives
20 |
21 | - For a more versatile hook, look at [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html).
22 | - For a "reverse timer", see [useCountdown()](/react-timing-hooks/loops-and-intervals/useCountdown.html).
23 |
24 | ## Example
25 |
26 | ```javascript
27 | import { useTimer } from 'react-timing-hooks'
28 |
29 | // this will count upwards every second
30 | const [timerValue] = useTimer(0, { startOnMount: true })
31 | return {timerValue}
32 | ```
33 |
34 | ## API
35 |
36 | `useTimer(start = 0, settings = {})`
37 | {: .fs-5 .fw-300 }
38 |
39 | ### Params
40 |
41 | | Name | Default | Description |
42 | |:----------------------|:-----------|:-----------------------------------------------------------------------------------------------------------|
43 | | start | `0` | The initial value of the timer |
44 | | settings.startOnMount | `false` | If true, the timer will immediately start on mount. If false, it has to be started manually via `start()`. |
45 | | settings.resetOnStop | `true` | If true, the timer will reset to the start value on stop. If false, it won't. |
46 | | settings.destroyIntervalOnPause | `true` | If false, the interval is kept running without doing anything until resumed. |
47 |
48 |
49 | ### Return value
50 |
51 | An array of format `[timerValue, counterControls]`, the first value is the current countdown value. This will be incremented by 1, every second.
52 |
53 | The second value is an object of counter controls (start, stop, pause, etc.), see [useCounter()](/react-timing-hooks/loops-and-intervals/useCounter.html#return-value).
54 |
55 |
56 |
--------------------------------------------------------------------------------
/docs/migrations/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: Migrations
4 | description: A list of migrations for breaking changes
5 | nav_order: 7
6 | has_children: true
7 | ---
8 |
9 | # Migrations
10 |
11 | This is a list of all migration guides.
12 |
--------------------------------------------------------------------------------
/docs/migrations/v1v2.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Migration to v2
3 | parent: Migrations
4 | nav_order: 1
5 | ---
6 |
7 | # Migration to v2
8 |
9 | Only the supported node version has been changed.
10 |
11 | If you were previously using Node 9 or lower, please install Node 10 or later and you're fine.
12 |
13 | Nothing else has been changed!
14 |
--------------------------------------------------------------------------------
/docs/migrations/v2v3.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Migration to v3
3 | parent: Migrations
4 | nav_order: 2
5 | ---
6 |
7 | # Migration to v3
8 |
9 | Support for Node 13 and below has been dropped.
10 |
11 | If you were previously using Node 13 or lower, please install Node 14 or later and then you're fine.
12 |
13 | Nothing else has been changed!
14 |
--------------------------------------------------------------------------------
/docs/migrations/v3v4.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Migration to v4
3 | parent: Migrations
4 | nav_order: 3
5 | ---
6 |
7 | # Migration to v4
8 |
9 | This guide will help you migrate from v3 (or lower) to v4, here is a **list of all changes**:
10 |
11 | ## Intervals don't immediately start on mount anymore
12 |
13 | Since v4, intervals won't start immediately on mount anymore.
14 |
15 | With the recent introduction of **interval controls** (start/stop, pause/resume etc.),
16 | all looping hooks could be started manually, but they were still starting immediately on
17 | mount like before. Since this is often undesired, all of these hooks (except for the clock)
18 | won't start on mount anymore. At least not by default. It can still be enabled via an option, though.
19 |
20 | ### Examples
21 |
22 | Intervals can be started via the returned `start` callback.
23 | Just call it upon a button click or inside a `useEffect`.
24 |
25 | ```javascript
26 | const { start } = useInterval(doSomething, 200)
27 | ```
28 |
29 | Starting the interval manually is **probably the best idea in most cases** –
30 | however, if you really want an interval to start immediately on mount, **you can still do that** by using the new interval options (an additional argument for most hooks), where you can set `startOnMount` to `true`, like so:
31 |
32 | ```javascript
33 | useInterval(doSomething, 200, { startOnMount: true })
34 | ```
35 |
36 | This breaking change affects:
37 |
38 | - `useInterval()`
39 | - `useCounter()`
40 | - `useTimer()`
41 | - `useCountdown()`
42 |
43 | ```javascript
44 | // APIs for the affected hooks
45 | const { start } = useInterval(doSomething, 200, { startOnMount: false })
46 | const [value, { start }] = useCounter({ start: 1, interval: 400, stepSize: 2, startOnMount: false })
47 | const [value, { start }] = useTimer(0, { startOnMount: false })
48 | const [value, { start }] = useCountdown(10, 0, { startOnMount: false })
49 | ```
50 |
51 | ## `useCountdown()` now has a mandatory end parameter
52 |
53 | The countdown hook is now a bit more than just a backwards-timer. It has now a
54 | mandatory end-parameter and will automatically stop when it's reached.
55 | Additionally, an event callback will be fired when this happens (see examples below).
56 |
57 | ### Examples
58 |
59 | ```javascript
60 | // BEFORE:
61 | // In v3 and below this would have counted down to infinity (or until it's manually stopped)
62 | const [counter] = useCountdown(10)
63 |
64 | // AFTER:
65 | // Since v4 this will count down to 0 and then stop by itself
66 | const [counter] = useCountdown(10, 0)
67 | ```
68 |
69 | To be notified when the countdown ends, you have to provide a callback to `options.onEnd()`.
70 |
71 | ```javascript
72 | // This will print a message when the countdown hits 0
73 | const [counter, { start }] = useCountdown(10, 0, {
74 | onEnd: () => console.log('Countdown has reached zero!')
75 | })
76 | ```
77 |
78 | ## The return value of `useTimer()` has changed
79 |
80 | To be aligned with all the other interval hooks like `useInterval()`, `useCounter()`, and `useCountdown()`,
81 | `useTimer()` now supports **interval controls** (like start, stop, pause etc.), too.
82 |
83 | This means instead of…
84 |
85 | ```javascript
86 | const timerValue = useTimer(0)
87 | ```
88 |
89 | …you now have to write:
90 |
91 | ```javascript
92 | const [timerValue] = useTimer(0)
93 | ```
94 |
95 | The benefit is that you can now pause and resume a timer like so:
96 |
97 | ```javascript
98 | const [timerValue, { pause, resume, isPaused }] = useTimer(0)
99 |
100 | return
103 | ```
104 |
105 | ## Timeouts spawned by `useTimeout` will not be debounced anymore
106 |
107 | Previously, timeouts spawned by `useTimeout()` were automatically debounced.
108 | This is **not the case anymore**. If you want to debounce your callbacks, there is now
109 | a dedicated hook for it, called **`useDebounce()`**
110 |
111 | ### Examples
112 |
113 | Take a look at the following example:
114 |
115 | ```javascript
116 | import { useState } from 'react'
117 | import { useTimeout } from 'react-timing-hooks'
118 |
119 | const HelloWorld = () => {
120 | const [output, setOutput] = useState(null)
121 | const onButtonClick = useTimeout(() => console.log('clicked'), 1000)
122 |
123 | return
124 |
125 |
{output}
126 |
127 | }
128 | ```
129 |
130 | If you were to click this button more than once in less than a second, `clicked` would've appeared only once in your console.
131 | At least in v3 that was the case. Now you would see it as often as you clicked – every callback is executed.
132 |
133 | However, it is often desired – especially for user input – to have it "debounced". For this there is now
134 | a dedicated hook which is called `useDebounce()`.
135 |
136 | This new hook does not function _exactly_ the same as the old `useTimeout()` hook though, because it **fires immediately**
137 | and _then_ blocks consecutive executions until the timeout expires. If you want the callback to fire **after** the timeout,
138 | you have to set the flag `options.fireAfterTimeout = true`.
139 |
140 | ```javascript
141 | import { useState } from 'react'
142 | import { useDebounce } from 'react-timing-hooks'
143 |
144 | const HelloWorld = () => {
145 | const [output, setOutput] = useState(null)
146 | const onButtonClick = useDebounce(() => console.log('clicked'), 1000)
147 |
148 | return
149 |
150 |
{output}
151 |
152 | }
153 | ```
154 |
--------------------------------------------------------------------------------
/docs/migrations/v4v5.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Migration to v5
3 | parent: Migrations
4 | nav_order: 4
5 | ---
6 |
7 | # Migration to v5
8 |
9 | This is a rather small breaking update. There have been changes to `useClock`'s pausing behaviour and `useCounter`'s stopping behaviour.
10 |
11 | ## Counters
12 |
13 | The counter hooks `useCounter`, `useTimer` will now be reset to their starting values when being stopped by default. The countdown hook `useCountdown` will not change, i.e. it will still not reset by default.
14 |
15 | However, you can opt-out of this new behaviour by setting `resetOnStop`. It's available on all counter based hooks.
16 |
17 | Additionally, all counter based hooks now receive a new control function called `reset()`, to manually reset the counter whenever you wish.
18 |
19 | ```javascript
20 | // If you want to keep the v4 behaviour, use:
21 | const [counter] = useTimer(0, { resetOnStop: false });
22 | ```
23 |
24 | ## Clock update
25 |
26 | By default, the clock will now keep running in the background when paused. This allows to show the correct time upon resuming.
27 |
28 | This behaviour can be opted-out of by setting `keepPausedClockRunningInBackground` to `false`.
29 |
--------------------------------------------------------------------------------
/docs/state/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: default
3 | title: State
4 | description: React hooks to create delayed or asynchronous useState() versions.
5 | nav_order: 5
6 | has_children: true
7 | ---
8 |
9 | # State
10 |
11 | React hooks that function similar to `useState()`.
12 | {: .fs-6 .fw-300 }
13 |
14 | These hooks are implemented using one or many of the low-level hooks included in `react-timing-hooks`.
15 |
--------------------------------------------------------------------------------
/docs/state/useThrottledState.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: useThrottledState
3 | description: A React hook to that throttles updates to useState().
4 | parent: State
5 | nav_order: 1
6 | ---
7 |
8 | # useThrottledState
9 |
10 | Manage rapidly changing state in your application without producing too many updates/re-renders!
11 | {: .fs-6 .fw-300 }
12 |
13 | This hook is based on a combination of `useThrottle()` & React's `useState()`.
14 |
15 | It allows you to throttle state updates, which in turn can reduce the amount of re-rerenders and/or effect
16 | updates. If you have a component, service, or interval that rapidly fires state updates, this hook allows
17 | you to do that without forcing an _actual_ update within React which would trigger a re-render.
18 |
19 | This is also helpful if you have a `useEffect()` hook that you don't want to run too often.
20 |
21 | {: .note-title }
22 | > Keep in mind
23 | >
24 | > This means that not every update is necessarily immediately reflected in the
25 | > state value, it might only be _queued_ for an update. But do not worry: no updates will be lost.
26 | > Eventually the latest call to the `setState` method will always be processed and cause an actual update.
27 |
28 | {: .highlight-title }
29 | > Typescript
30 | >
31 | > Like `useState()`, `useThrottledState()` is also generic to define the type of the state value.
32 |
33 | ## Example
34 |
35 | ```javascript
36 | import { useThrottledState } from 'react-timing-hooks'
37 |
38 | const Comp = () => {
39 | // Allow state to be only updated once every second.
40 | const [count, setCount] = useThrottledState(0, 1_000)
41 |
42 | // Imagine you have some sort of rapid firing state updates.
43 | // This example uses a very short interval of 10ms, just as an example.
44 | useInterval(() => setCount(count + 1), 10)
45 |
46 | // Because of "useThrottledState", the actual value of "count"
47 | // will only be changed every second. So you'll see something like
48 | // 1, 11, 21, 31, ...
49 | return {count}
50 | }
51 | ```
52 |
53 | ## API
54 |
55 | `useThrottledState(initialState: T, delayInMs: number)`
56 | {: .fs-5 .fw-300 }
57 |
58 | ### Params
59 |
60 | | Name | Description |
61 | |:-----------------|:----------------------------------------------------------------------|
62 | | initialState | The initial state, like in `useState()`. |
63 | | delayInMs | the minimum delay between two state updates. |
64 |
65 | ### Return value
66 |
67 | An array of form: [state: T, setState: (newState: T) => void], similar to `useState()`.
68 |
69 | | Name | Description |
70 | |:-----------------|:----------------------------------------------------------------------------------------------------|
71 | | state | The current (albeit throttled) state value. |
72 | | setState | The setter to queue a change/update to the state. Will be processed as soon as the delay allows it. |
73 |
74 | ### Generic type
75 |
76 | Usage is similar to `useState()`. The generic type `T` defines the type of the state.
--------------------------------------------------------------------------------
/integration-tests/helpers.ts:
--------------------------------------------------------------------------------
1 | /*
2 | react-test-renderer seems to schedule timeouts with _flushCallback and 0ms timeout which pollute this test
3 | This function get's rid of those without removing our own timeouts
4 | */
5 | import { act } from 'react'
6 |
7 | export const removeFlushTimers = () => {
8 | act(() => {
9 | jest.advanceTimersByTime(1)
10 | })
11 | }
12 |
--------------------------------------------------------------------------------
/integration-tests/useAnimationFrame.test.tsx:
--------------------------------------------------------------------------------
1 | import { render, fireEvent } from '@testing-library/react'
2 | import React, { act, useEffect, useState } from 'react'
3 | import { useAnimationFrame } from '../.tmp/index'
4 | // @ts-ignore
5 | import { animationFrame } from '@shopify/jest-dom-mocks'
6 |
7 | const TestComponent: React.FC = () => {
8 | const [output, setOutput] = useState('initial')
9 | const [invokeRequest, setInvokeRequest] = useState(false)
10 |
11 | const setOutputNextFrame = useAnimationFrame(setOutput)
12 |
13 | useEffect(() => {
14 | if (invokeRequest) {
15 | setOutputNextFrame('foobar')
16 | }
17 | }, [invokeRequest])
18 |
19 | return (
20 |