Merge pull request #25 from streamich/get-set

Get set
This commit is contained in:
Va Da 2018-10-29 15:09:19 +01:00 committed by GitHub
commit aa4c3d997a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 156 additions and 0 deletions

View File

@ -54,6 +54,7 @@
- [`useSpring`](./docs/useSpring.md) — interpolates number over time according to spring dynamics.
- [`useTimeout`](./docs/useTimeout.md) — returns true after a timeout.
- [`useTween`](./docs/useTween.md) — re-renders component, while tweening a number from 0 to 1. [![][img-demo]](https://codesandbox.io/s/52990wwzyl)
- [`useUpdate`](./docs/useUpdate.md) — returns a callback, which re-renders component when called.
<br/>
<br/>
- [**Side-effects**](./docs/Side-effects.md)
@ -71,6 +72,7 @@
<br/>
<br/>
- [**State**](./docs/State.md)
- [`useGetSet`](./docs/useGetSet.md) &mdash; returns state getter `get()` instead of raw state.
- [`useObservable`](./docs/useObservable.md) &mdash; tracks latest value of an `Observable`.
- [`useSetState`](./docs/useSetState.md) &mdash; creates `setState` method which works like `this.setState`. [![][img-demo]](https://codesandbox.io/s/n75zqn1xp0)
- [`useToggle`](./docs/useToggle.md) &mdash; tracks state of a boolean.

46
docs/useGetSet.md Normal file
View File

@ -0,0 +1,46 @@
# `useGetSet`
React state hook that returns state getter function instead of
raw state itself, this prevents subtle bugs when state is used
in nested functions.
## Usage
Below example uses `useGetSet` to increment a number after 1 second
on each click.
```jsx
import {useGetSet} from 'react-use';
const Demo = () => {
const [get, set] = useGetSet(0);
const onClick = () => {
setTimeout(() => {
set(get() + 1)
}, 1_000);
};
return (
<button onClick={onClick}>Clicked: {get()}</button>
);
};
```
If you would do this example in a naive way using regular `useState`
hook, the counter would not increment correctly if you click fast multiple times.
```jsx
const DemoWrong = () => {
const [cnt, set] = useState(0);
const onClick = () => {
setTimeout(() => {
set(cnt + 1)
}, 1_000);
};
return (
<button onClick={onClick}>Clicked: {cnt}</button>
);
};
```

21
docs/useUpdate.md Normal file
View File

@ -0,0 +1,21 @@
# `useUpdate`
React utility hook that returns a function that forces component
to re-render when called.
## Usage
```jsx
import {useUpdate} from 'react-use';
const Demo = () => {
const update = useUpdate();
return (
<>
<div>Time: {Date.now()}</div>
<button onClick={update}>Update</button>
</>
);
};
```

View File

@ -0,0 +1,40 @@
import * as React from 'react';
import {storiesOf} from '@storybook/react';
import {useGetSet} from '..';
import {useState} from '../react';
import ShowDocs from '../util/ShowDocs';
const Demo = () => {
const [get, set] = useGetSet(0);
const onClick = () => {
setTimeout(() => {
set(get() + 1)
}, 1_000);
};
return (
<button onClick={onClick}>Clicked: {get()}</button>
);
};
const DemoWrong = () => {
const [cnt, set] = useState(0);
const onClick = () => {
setTimeout(() => {
set(cnt + 1)
}, 1_000);
};
return (
<button onClick={onClick}>Clicked: {cnt}</button>
);
};
storiesOf('useGetSet', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useGetSet.md')} />)
.add('Demo', () =>
<Demo/>
)
.add('DemoWrong', () =>
<DemoWrong/>
)

View File

@ -0,0 +1,21 @@
import {storiesOf} from '@storybook/react';
import * as React from 'react';
import {useUpdate} from '..';
import ShowDocs from '../util/ShowDocs';
const Demo = () => {
const update = useUpdate();
return (
<>
<div>Time: {Date.now()}</div>
<button onClick={update}>Update</button>
</>
);
};
storiesOf('useUpdate', module)
.add('Docs', () => <ShowDocs md={require('../../docs/useUpdate.md')} />)
.add('Demo', () =>
<Demo/>
)

View File

@ -5,6 +5,7 @@ import useCounter from './useCounter';
import useCss from './useCss';
import useFavicon from './useFavicon';
import useGeolocation from './useGeolocation';
import useGetSet from './useGetSet';
import useHover from './useHover';
import useIdle from './useIdle';
import useLifecycles from './useLifecycles';
@ -30,6 +31,7 @@ import useTitle from './useTitle';
import useToggle from './useToggle';
import useTween from './useTween';
import useUnmount from './useUnmount';
import useUpdate from './useUpdate';
import useWindowSize from './useWindowSize';
export {
@ -40,6 +42,7 @@ export {
useCss,
useFavicon,
useGeolocation,
useGetSet,
useHover,
useIdle,
useLifecycles,
@ -65,5 +68,6 @@ export {
useToggle,
useTween,
useUnmount,
useUpdate,
useWindowSize,
};

17
src/useGetSet.ts Normal file
View File

@ -0,0 +1,17 @@
import {useRef} from './react';
import useUpdate from './useUpdate';
const useGetSet = <T>(initialValue: T): [() => T, (value: T) => void] => {
const update = useUpdate();
let state = useRef(initialValue);
const get = () => state.current;
const set = (value: T) => {
state.current = value;
update();
};
return [get, set];
};
export default useGetSet;

5
src/useUpdate.ts Normal file
View File

@ -0,0 +1,5 @@
import {useState} from './react';
const useUpdate = () => useState(0)[1] as (() => void);
export default useUpdate;