An open API service indexing awesome lists of open source software.

https://github.com/haensl/hooks

Assorted React hooks.
https://github.com/haensl/hooks

debounce hooks react react-components react-hooks reactjs requestanimationframe

Last synced: 3 months ago
JSON representation

Assorted React hooks.

Awesome Lists containing this project

README

        

# @haensl/react-hooks

Assorted React hooks.

[![NPM](https://nodei.co/npm/@haensl%2Freact-hooks.png?downloads=true)](https://nodei.co/npm/@haensl%2Freact-hooks/)

[![npm version](https://badge.fury.io/js/@haensl%2Freact-hooks.svg)](http://badge.fury.io/js/@haensl%2Freact-hooks)
[![CircleCI](https://circleci.com/gh/haensl/hooks.svg?style=svg)](https://circleci.com/gh/haensl/hooks)

## Installation

### Via `npm`

```bash
$ npm install -S @haensl/react-hooks
```

### Via `yarn`

```bash
$ yarn add @haensl/react-hooks
```

## Usage

1. [Install @haensl/react-hooks](#installation)

2. Use hooks in your components:

```javascript
import { useDebounce } from '@haensl/react-hooks';

const DebouncedButton = () => {
const handler = useDebounce(() => {
console.log('click');
}, 50);

return (
click me
);
};
```

## Available hooks

* [`useAnimationFrame`](#useAnimationFrame): animate a function.
* [`useBoundingClientRect`](#useBoundingClientRect): keep track of a container's [DOM rectangle](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
* [`useClassNames`](#useClassNames): compile CSS class names from state.
* [`useDebounce`](#useDeboune): debounce a function.
* [`useInterval`](#useInterval): use an interval.
* [`useIsMounted`](#useIsMounted): keep track of whether or not a component is mounted.
* [`useIsomorphicLayoutEffect`](#useIsomorphicLayoutEffect): use this instead of [`useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) if your app uses serverside rendering (SSR).
* [`useIsScrolling`](#useIsScrolling): keep track of whether or not the user is scrolling.
* [`useLang`](#useLang): use the browser's language setting.
* [`useOnScroll`](#useOnScroll): subscribe to scroll events.
* [`usePrevious`](#usePrevious): keep track of a variable's previous value.
* [`useTimeout`](#useTimeout): use a timeout.
* [`useWindowScroll`](#useWindowScroll): keep track of the `window`'s scroll position.
* [`useWindowSize`](#useWindowSize): keep track of the `window`'s size.

### `useAnimationFrame(fn)`

Uses [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) to animate a function `fn`. The callback is passed one single argument, the time delta in milliseconds that has passed between this and the last call. Please check the [example](#useAnimationFrameExample) below as well as the [Codepen example](https://codepen.io/haensl/pen/GRoNGNB).

##### Example

```javascript
import React, { useState, useEffect } from 'react';
import { useAnimationFrame } from '@haensl/react-hooks';

const AnimatedTimer = () => {
const [seconds, setSeconds] = useState(0);
const [elapsed, setElapsed] = useState(0);

useAnimationFrame((dt) => {
setElapsed(elapsed + dt);
});

useEffect(() => {
if (elapsed >= 1000) {
setSeconds(seconds + 1);
setElapsed(elapsed - 1000);
}
}, [elapsed]);

return (
{ seconds }
);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/GRoNGNB)

### `useBoundingClientRect(ref, [debounceMs = 25])`
Returns the DOM rectangle _(initially `null`)_ as returned by [`getBoundingClientRect`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect) for the given container `ref`. Changes are debounced by 25 milliseconds by default. Customize the debounce interval via the optional `debounceMs` argument. Please check out the [example below](#useBoundingClientRectExample) as well as the [Codepen example](https://codepen.io/haensl/pen/YzwxqOq).

#### Example
```javascript
import React, { useRef } from 'react';
import { useBoundingClientRect } from '@haensl/react-hooks';

const RectTracker = () => {
const ref = useRef();
const containerRect = useBoundingClientRect(ref);

if (!containerRect) {
return (


no container rect

);
}

return (


Container rect:
Width: {containerRect.width}
Height: {containerRect.height}

);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/YzwxqOq)

### `useClassNames(states, [separator = ' '])`

Compiles a `states` object into a CSS class name string. By default all keys in `states` are joined by a space (`' '`) but you can supply a custom `separator` to cater to the needs of your CSS module naming methodology of choice. Please check the [examples below](#useClassNamesExample).

#### Example

```javascript
import React, { useState } from 'react';
import { useClassNames } from '@haensl/react-hooks';

const MyComponent = () => {
const [stateA, setStateA] = useState(false);
const className = useClassNames({
MyComponent: true, // always have MyComponent in class name
MyComponent--stateA: stateA // add MyComponent--stateA when stateA is true
});

// className will be 'MyComponent' or 'MyComponent MyComponent--stateA'

return (


{
// render content
}

);
};
```

#### Example: custom separator

```javascript
import React, { useState } from 'react';
import { useClassNames } from '@haensl/react-hooks';

const MyComponent = () => {
const [stateA, setStateA] = useState(false);
const className = useClassNames(
{
MyComponent: true, // always have MyComponent in class name
stateA // add --stateA when stateA is true
},
'--'
);

// className will either be 'MyComponent' or 'MyComponent--stateA'

return (


{
// render content
}

);
};
```

### `useDebounce(fn, debounceMs)`

Uses [memoization](https://reactjs.org/docs/hooks-reference.html#usememo) to debounce `fn` by `debounceMs` milliseconds. Please check the [example below](#useDebounceExample) as well as the [Codepen example](https://codepen.io/haensl/pen/eYJBKEZ).

##### Example

```javascript
import React from 'react';
import { useDebounce } from '@haensl/react-hooks';

const DebouncedButton = () => {
const handler = useDebounce(() => {
console.log('click');
}, 50); // handler only fires when there were no calls for 50ms.

return (
click me
);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/eYJBKEZ)

### `useInterval(fn, intervalMs)`

Calls a `fn` repeatedly every `intervalMs` milliseconds.

##### Example

```javascript
import React, { useState, useCallback } from 'react';
import { useInterval } from '@haensl/react-hooks';

const MyAnimation = () => {
const [frame, setFrame] = useState(0);

// Update frame every 100 milliseconds
useInterval(() => {
setFrame((frame) => frame + 1);
}, 100);

return (

{ frame }

);
};
```

### `useIsMounted()`

Returns a `function` to check whether or not the component invoking the hook is mounted.

##### Example

```javascript
import React, { useEffect } from 'react';
import { useIsMounted } from '@haensl/react-hooks';
import api from 'somewhere';

const MyComponent = () => {
const isMounted = useIsMounted();
// load some data from the backend
useEffect(() => {
api.fetchData()
.then((data) => {
if (isMounted()) {
// use data only if component is still mounted
}
});
}, []);
}
```

### `useIsomorphicLayoutEffect(fn, deps)`

This hooks resolves the common React warning when using `useLayoutEffect` in a serverside environment:

*Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer’s output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://fb.me/react-uselayouteffect-ssr for common fixes.*

`useIsomorphicLayoutEffect` resolves to [`useLayoutEffect`](https://reactjs.org/docs/hooks-reference.html#uselayouteffect) on the client and [`useEffect`](https://reactjs.org/docs/hooks-reference.html#useeffect) on the server. Use this hook instead of `useLayoutEffect` if your app uses serverside rendering (SSR).

##### Example

```javascript
import React, { useRef } from 'react';
import { useIsomorphicLayoutEffect } from '@haensl/react-hooks';

const MyComponent = () => {
const ref = useRef();

// prevents serverside rendering warning
useIsomorphicLayoutEffect(() => {
if (ref.current) {
// do stuff with ref
}
}, [ref]);

return (


// ...

)
}
```

### `useIsScrolling([el = window, scrollEndMs = 100])`

Returns a `boolean` indicating whether or not the user is scrolling. You can subscribe to a specific element via the first argument, `el` _(default: `window`)_. End of scrolling is determined by no incoming scroll events for `scrollEndMs` milliseconds _(default: `100`)_. Please check the [example blow](#useIsScrollingExample) as well as the [Codepen example](https://codepen.io/haensl/pen/qBbqeWz)

##### Example

```javascript
import React from 'react';
import { useIsScrolling } from '@haensl/react-hooks';

const UserScrollTracker = () => {
const isScrolling = useIsScrolling();

return (
The user is currently { isScrolling ? '' : 'not' } scrolling
);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/qBbqeWz)

### `useLang({ defaultLang = 'en' }) => string`

Returns the user's language setting from [`navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/language). Use the `defaultLang` of the options parameter to set a default language. _(default: `'en`)_.

##### Example

```javascript
import React from 'react';
import { useLang } from '@haensl/react-hooks';

const MyComponent = () => {
const lang = useLang();

return (
The user's preferred language is { lang }.
);
};
```

### `useOnScroll(fn, [el = window])`

Subscribes to [`scroll`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll_event) events on the given element `el` _(default: `window`)_. The callback function `fn` is passed the [`Event`](https://developer.mozilla.org/en-US/docs/Web/API/Element/scroll_event). Please check the [example below](#useOnScrollExample) as well as the [Codepen example](https://codepen.io/haensl/pen/wvMoLJK).

##### Example

```javascript
import React, { useState } from 'react';
import { useOnScroll } from '@haensl/react-hooks';

const WindowScrollTracker = () => {
const [windowScroll, setWindowScroll] = useState(0);

useOnScroll(() => {
setWindowScroll(window.scrollY);
});

return (


Window has scrolled down
{ windowScroll }px

);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/wvMoLJK)

### `usePrevious(value)`

Keeps track of changes to a value, storing it's _previous_ state.

##### Example

```javascript
import { useEffect, useState } from 'react';
import { usePrevious, useWindowScroll } from '@haensl/react-hooks';

const ScrollDirectionTracker = () => {
const scrollPosition = useWindowScroll();
const previousScrollPosition = usePrevious(scrollPosition);
const [scrollDirection, setScrollDirection] = useState('down');

useEffect(() => {
if (previousScrollPosition.y < scrollPosition.y) {
setScrollDirection('down');
} else if (previousScrollPosition.y > scrollPosition.y) {
setScrollDirection('up');
}
}, [scrollPosition, previousScrollPosition]);

return (


User is scrolling
{ scrollDirection }px

);
};
```

### `useTimeout(fn, timeoutMs = 0)`

Calls `fn` once after `intervalMs` milliseconds.

##### Example

```javascript
import React, { useState, useCallback } from 'react';
import { useClassNames, useTimeout } from '@haensl/react-hooks';

const MyComponent = () => {
const [animate, setAnimate] = useState(false);

// Start animation after 1s
useTimeout(() => {
setAnimate(true);
}, 1000);

const className = useClassNames({
animate
});

return (


// ...

);
};
```

### `useWindowScroll([debounceMs = 25])`
Returns an object _(`null` if there is no `window`)_ with properties `x` and `y` reflecting the the scroll position of the `window` or `document`. Scroll position updates are by default debounced by 25 milliseconds. This debounce interval can be customized via the optional `debounceMs` argument. Please check the [example below](#useWindowScrollExample) as well as the [Codepen example](https://codepen.io/haensl/pen/VweMJGm).

#### Example

```javascript
import React, { useState } from 'react';
import { useWindowScroll } from '@haensl/react-hooks';

const windowScrollTracker = () => {
const windowScroll = useWindowScroll();

if (!windowScroll) {
return (


no scroll poistion

);
}

return (


Scroll x: {windowScroll.x}
Scroll y: {windowScroll.y}

);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/VweMJGm)

### `useWindowSize([debounceMs = 25])`
Returns an object _(initially `null`)_ with properties `width` and `height` reflecting the `innerWidth` and `innerHeight` of the `window` object. Size updates are by default debounced by 25 milliseconds. This debounce interval can be customized via the optional `debounceMs` argument. Please check the [example below](#useWindowSizeExample) as well as the [Codepen example](https://codepen.io/haensl/pen/mdVMVxY).

#### Example

```javascript
import React, { useState } from 'react';
import { useWindowSize } from '@haensl/react-hooks';

const WindowSizeTracker = () => {
const windowSize = useWindowSize();

if (!windowSize) {
return (


No window size

);
}

return (


Window Size:
width: { windowSize.width }px
height: { windowSize.height }px

);
};
```

#### [→ Codepen example](https://codepen.io/haensl/pen/mdVMVxY)

## [Changelog](CHANGELOG.md)

## [License](LICENSE)