mirror of
https://github.com/streamich/react-use.git
synced 2025-12-08 18:02:14 +00:00
feat: 🎸 add useGetSetState
This commit is contained in:
parent
efa9acd988
commit
dcd1013736
@ -75,6 +75,7 @@
|
||||
<br/>
|
||||
- [**State**](./docs/State.md)
|
||||
- [`useGetSet`](./docs/useGetSet.md) — returns state getter `get()` instead of raw state.
|
||||
- [`useGetSetState`](./docs/useGetSetState.md) — as if [`useGetSet`](./docs/useGetSet.md) and [`useSetState`](./docs/useSetState.md) had a baby.
|
||||
- [`useObservable`](./docs/useObservable.md) — tracks latest value of an `Observable`.
|
||||
- [`useSetState`](./docs/useSetState.md) — creates `setState` method which works like `this.setState`. [![][img-demo]](https://codesandbox.io/s/n75zqn1xp0)
|
||||
- [`useToggle` and `useBoolean`](./docs/useToggle.md) — tracks state of a boolean.
|
||||
|
||||
23
docs/useGetSetState.md
Normal file
23
docs/useGetSetState.md
Normal file
@ -0,0 +1,23 @@
|
||||
# `useGetSetState`
|
||||
|
||||
A mix of `useGetSet` and `useGetSetState`.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import {useGetSetState} from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const [get, setState] = useGetSetState({cnt: 0});
|
||||
const onClick = () => {
|
||||
setTimeout(() => {
|
||||
setState({cnt: get().cnt + 1})
|
||||
}, 1_000);
|
||||
};
|
||||
|
||||
return (
|
||||
<button onClick={onClick}>Clicked: {get().cnt}</button>
|
||||
);
|
||||
};
|
||||
```
|
||||
23
src/__stories__/useGetSetState.story.tsx
Normal file
23
src/__stories__/useGetSetState.story.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import * as React from 'react';
|
||||
import {storiesOf} from '@storybook/react';
|
||||
import {useGetSetState, useSetState} from '..';
|
||||
import ShowDocs from '../util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const [get, setState] = useGetSetState<{cnt: number}>({cnt: 0});
|
||||
const onClick = () => {
|
||||
setTimeout(() => {
|
||||
setState({cnt: get().cnt + 1})
|
||||
}, 1_000);
|
||||
};
|
||||
|
||||
return (
|
||||
<button onClick={onClick}>Clicked: {get().cnt}</button>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('useGetSetState', module)
|
||||
.add('Docs', () => <ShowDocs md={require('../../docs/useGetSetState.md')} />)
|
||||
.add('Demo', () =>
|
||||
<Demo/>
|
||||
)
|
||||
@ -7,6 +7,7 @@ import useCss from './useCss';
|
||||
import useFavicon from './useFavicon';
|
||||
import useGeolocation from './useGeolocation';
|
||||
import useGetSet from './useGetSet';
|
||||
import useGetSetState from './useGetSetState';
|
||||
import useHover from './useHover';
|
||||
import useIdle from './useIdle';
|
||||
import useLifecycles from './useLifecycles';
|
||||
@ -45,6 +46,7 @@ export {
|
||||
useFavicon,
|
||||
useGeolocation,
|
||||
useGetSet,
|
||||
useGetSetState,
|
||||
useHover,
|
||||
useIdle,
|
||||
useLifecycles,
|
||||
|
||||
@ -48,7 +48,7 @@ const useAudio = (props: AudioProps): [React.ReactElement<AudioProps>, AudioStat
|
||||
|
||||
const onPlay = () => setState({isPlaying: true});
|
||||
const onPause = () => setState({isPlaying: false});
|
||||
const onVolumeChange = (event) => {
|
||||
const onVolumeChange = () => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
setState({
|
||||
@ -56,7 +56,7 @@ const useAudio = (props: AudioProps): [React.ReactElement<AudioProps>, AudioStat
|
||||
volume: el.volume,
|
||||
});
|
||||
};
|
||||
const onDurationChange = (event) => {
|
||||
const onDurationChange = () => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
const {duration, buffered} = el;
|
||||
@ -70,7 +70,7 @@ const useAudio = (props: AudioProps): [React.ReactElement<AudioProps>, AudioStat
|
||||
if (!el) return;
|
||||
setState({time: el.currentTime});
|
||||
};
|
||||
const onProgress = (event) => {
|
||||
const onProgress = () => {
|
||||
const el = ref.current;
|
||||
if (!el) return;
|
||||
setState({buffered: parseTimeRanges(el.buffered)});
|
||||
@ -102,7 +102,7 @@ const useAudio = (props: AudioProps): [React.ReactElement<AudioProps>, AudioStat
|
||||
if (!lockPlay) {
|
||||
const promise = el.play();
|
||||
const isPromise = typeof promise === 'object';
|
||||
|
||||
|
||||
if (isPromise) {
|
||||
lockPlay = true;
|
||||
const resetLock = () => {
|
||||
@ -152,14 +152,14 @@ const useAudio = (props: AudioProps): [React.ReactElement<AudioProps>, AudioStat
|
||||
if (!el) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
console.error(
|
||||
'useAudio() ref to <audio> element is empty at mount. ' +
|
||||
'useAudio() ref to <audio> element is empty at mount. ' +
|
||||
'It seem you have not rendered the audio element, which is ' +
|
||||
'returns as the first argument const [audio] = useAudio(...).'
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// Start media, if autoPlay requested.
|
||||
if (props.autoPlay && el.paused) {
|
||||
controls.play();
|
||||
|
||||
28
src/useGetSetState.ts
Normal file
28
src/useGetSetState.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {useRef} from './react';
|
||||
import useUpdate from './useUpdate';
|
||||
|
||||
const useGetSetState = <T extends object>(initialState: T = {} as T): [() => T, (patch: Partial<T>) => void]=> {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof initialState !== 'object') {
|
||||
throw new TypeError('useGetSetState initial state must be an object.');
|
||||
}
|
||||
}
|
||||
|
||||
const update = useUpdate();
|
||||
const state = useRef<T>({...(initialState as object)} as T);
|
||||
const get = () => state.current;
|
||||
const set = (patch: Partial<T>) => {
|
||||
if (!patch) return;
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof patch !== 'object') {
|
||||
throw new TypeError('useGetSetState setter patch must be an object.');
|
||||
}
|
||||
}
|
||||
Object.assign(state.current, patch);
|
||||
update();
|
||||
};
|
||||
|
||||
return [get, set];
|
||||
};
|
||||
|
||||
export default useGetSetState;
|
||||
Loading…
x
Reference in New Issue
Block a user