@conodene/usetimeout-react-hook
Version:
React.js custom hook that sets a leak-safe timeout and returns a function to cancel it before the timeout expires.
183 lines (140 loc) • 8.44 kB
Markdown
<h1 align="center">usetimeout-react-hook</h1>
<p>
<a href="https://travis-ci.org/jkomyno/usetimeout-react-hook.svg?branch=master">
<img alt="Build Status" src="https://travis-ci.org/jkomyno/usetimeout-react-hook.svg?branch=master" target="_blank" />
</a>
<a href="https://coveralls.io/github/jkomyno/usetimeout-react-hook?branch=master">
<img alt="Coverage Status" src="https://coveralls.io/repos/jkomyno/usetimeout-react-hook/badge.svg?branch=master" target="_blank" />
</a>
<img alt="Version" src="https://img.shields.io/badge/version-0.1.2-blue.svg?cacheSeconds=2592000" />
<a href="https://github.com/jkomyno/usetimeout-react-hook#readme">
<img alt="Documentation" src="https://img.shields.io/badge/documentation-yes-brightgreen.svg" target="_blank" />
</a>
<a href="https://github.com/jkomyno/usetimeout-react-hook/graphs/commit-activity">
<img alt="Maintenance" src="https://img.shields.io/badge/Maintained%3F-yes-green.svg" target="_blank" />
</a>
<a href="https://github.com/jkomyno/usetimeout-react-hook/blob/master/LICENSE">
<img alt="License: MIT" src="https://img.shields.io/badge/License-MIT-yellow.svg" target="_blank" />
</a>
</p>
> React.js custom hook that sets a leak-safe timeout and returns a function to cancel it before the timeout expires.
## Install
```sh
npm install usetimeout-react-hook
```
## 🔑 Key features
* 🥇 inspired by [this awesome blog post](https://overreacted.io/making-setinterval-declarative-with-react-hooks) by [Dan Abramov](https://github.com/gaearon)
* ⚠️ optional manual cancelability of timeout
* ✨ uses [useEffect](https://reactjs.org/docs/hooks-effect.html) dependencies array as a policy to dictate the hook updates, by default no dependency is specified
* 💪 written in TypeScript
* ✔️ 100% test coverage
## 🤔 Yet another setTimeout hook, why?
If you search something among the lines of [react-use-timeout](https://www.npmjs.com/search?q=react-use-timeout) a number of results
appear. Why was this package necessary?
Most of the other timeout hook packages I've glanced at had the following shortcomings:
* stuck with setTimeout, with no generic timer support
* no custom re-render policy
* no tests in place
Sometimes user needs the ability to use a custom timer, since `setTimeout` may not always be the best choice, especially in
React Native applications. In fact, the primary reason I built this custom hook was to expose a customizable and reusable
timeout manager for an other package of mine, [react-native-user-inactivity](https://github.com/jkomyno/react-native-user-inactivity).
A number of users had pointed out that on **React Native** there were the following issues with `setTimeout`:
* it would cause a crash on Android after many minutes of timeout
* it would simply stop working when the application is in background
Hopefully this package will be useful to others as well.
## ❔ How to use
This package exposes two hooks, [useTimeoutDefault](src/useTimeoutDefault.ts) and [useTimeout](src/useTimeout.ts).
Actually, the first one is just a wrapper for the second, and uses the standard `setTimeout` and `clearTimeout` as
timeout handler methods.
Since useTimeoutDefault is what many users probably need the most, it's the default exported package.
Each of this hook return a single function, which can be optionally used to manually cancel the timeout before it expires.
The type of this function, `CancelTimer`, is: `() => void`.
The signature of `useTimeoutDefault` is the following:
```typescript
import useTimeoutDefault from 'usetimeout'; // notice that it's a default import
/**
* useTimeoutDefault is a React.js custom hook that sets a leak-safe timeout and returns
* a function to cancel it before the timeout expires.
* It uses the default timeout handlers, i.e. window.setTimeout and window.clearTimeout.
* It's composed of two other native hooks, useRef and useEffect.
* If a new callback is given to the hook before the previous timeout expires,
* only the new callback will be executed at the moment the timeout expires.
* When the hook receives a new callback, the timeout isn't reset.
*
* @param callback the function to be executed after the timeout expires
* @param timeout the number of milliseconds after which the callback should be triggered
* @param deps useEffect dependencies that should cause the timeout to be reset
* @return function to cancel the timer before the timeout expires
*/
type UseTimeoutDefault = (callback: () => void, timeout: number, deps?: unknown[]) => CancelTimer;
```
Since `usetimeout` supports a generic timer, it requires an implementation of the TimeoutHandler interface, which is defined as:
```typescript
interface TimeoutHandler<T> {
/**
* Timeout function that accepts two parameters:
* a function and the timeout after which that function is fired.
* If not provided, the default `setTimeout` implementation will be
* the standard `window.setTimeout`.
*/
setTimeout: (fn: () => void, timeout: number) => T;
/**
* Function that should be used to clear the effects of `setTimeout` after
* the component where it is rendered is unmounted.
* If not provided, the default `clearTimeout` implementation will be
* the standard `window.clearTimeout`.
*/
clearTimeout: (timeout: T | undefined) => void;
}
```
The signature of `useTimeout` is the following:
```typescript
import { useTimeout } from 'usetimeout'; // notice that it's a named import
/**
* useTimeout is a React.js custom hook that sets a leak-safe timeout and returns
* a function to cancel it before the timeout expires.
* It's composed of two other native hooks, useRef and useEffect.
* It requires a custom way of setting a timeout and clearing it, expressed as an implementation
* of the generic TimeoutHandler<T> interface.
* The timer is restarted every time an item in `deps` changes.
* If a new callback is given to the hook before the previous timeout expires,
* only the new callback will be executed at the moment the timeout expires.
* When the hook receives a new callback, the timeout isn't reset.
*
* @param callback the function to be executed after the timeout expires
* @param timeout the number of milliseconds after which the callback should be triggered
* @param timeHandler TimeoutHandler instance that's used to set and clear the timeout
* @param deps useEffect dependencies that should cause the timeout to be reset
* @return function to cancel the timer before the timeout expires
*/
type UseTimeout = <T>(callback: () => void, timeout: number, timeHandler: TimeoutHandler<T>, deps?: unknown[]) => CancelTimer;
```
---------------------------------------------------------
## ✔️ Run tests
Tests are run using [**jest**](https://jestjs.io), at the end of the test a coverage table should appear.
```sh
npm run test
```
## 🚀 Build package
This package is built using **TypeScript**, so the source needs to be converted in JavaScript before being usable by the users.
**usetimeout** uses [**Rollup**](https://rollupjs.org) as build system, and the JavaScript module formats it's been configured to support are:
* CommonJS: module format used by Node (using `require` function).
* ESM: modern module format (using `import` syntax).
* UMD: Universal Module Definition, to be able to import it directly in the browser (not as popular these days).
```sh
npm run build
```
## 👤 Author
**Alberto Schiabel**
* Github: [](https://github.com/jkomyno)
## 🤝 Contributing
Contributions, issues and feature requests are welcome!<br />Feel free to check [issues page](https://github.com/jkomyno/usetimeout-react-hook/issues).
The code is short, throughly commented and well tested, so you should feel quite comfortable working on it.
If you have any doubt or suggestion, please open an issue.
## 🦄 Show your support
Give a ⭐️ if this project helped or inspired you!
## 📝 License
Built with ❤️ by [Alberto Schiabel](https://github.com/jkomyno).<br />
This project is [MIT](https://github.com/jkomyno/usetimeout-react-hook/blob/master/LICENSE) licensed.
## Related packages
* [react-native-user-inactivity](https://github.com/jkomyno/react-native-user-inactivity)