Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add useResetState hook #2552

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
- [`useRendersCount`](./docs/useRendersCount.md) — count component renders. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-userenderscount--demo)
- [`createGlobalState`](./docs/createGlobalState.md) — cross component shared state.[![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-createglobalstate--demo)
- [`useMethods`](./docs/useMethods.md) — neat alternative to `useReducer`. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-usemethods--demo)
- [`useResetState`](./docs/useResetState.md) — hooks that provide methods to reset state. [![][img-demo]](https://streamich.github.io/react-use/?path=/story/state-useresetstate--demo)
<br/>
<br/>
- [**Miscellaneous**]()
Expand Down
38 changes: 38 additions & 0 deletions docs/useResetState.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# `useResetState`

Hooks that provide methods to reset state,resets the state to its initial value.

## Usage

```jsx
import {useResetState} from 'react-use';

const Demo = () => {
const [state, setState, resetState] = useResetState({
foo: '',
count: 0
});

return (
<div>
<pre>{JSON.stringify(state, null, 2)}</pre>
<button onClick={(prev) => setState(prev => ({foo: 'bar', count: prev.count + 1}))}>set bar and count ++</button>
<button onClick={() => resetState()}>resetState</button>
</div>
);
};

```


## Reference

```js
const [state, setState, resetState] = useResetState({
foo: '',
count: 0
});

setState(prev => ({foo: 'bar', count: prev.count + 1}));
resetState();
```
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ export { default as useShallowCompareEffect } from './useShallowCompareEffect';
export { default as useSize } from './useSize';
export { default as useSlider } from './useSlider';
export { default as useSpeech } from './useSpeech';
export { default as useResetState } from './useResetState';
// not exported because of peer dependency
// export { default as useSpring } from './useSpring';
export { default as useStartTyping } from './useStartTyping';
Expand Down
18 changes: 18 additions & 0 deletions src/useResetState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { useState, useCallback } from 'react';
import type { Dispatch, SetStateAction } from 'react';

type ResetState = () => void;

const useResetState = <S>(
initialState: S | (() => S)
): [S, Dispatch<SetStateAction<S>>, ResetState] => {
const [state, setState] = useState(initialState);

const resetState = useCallback(() => {
setState(initialState);
}, [initialState]);

return [state, setState, resetState];
};

export default useResetState;
25 changes: 25 additions & 0 deletions stories/useResetState.story.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { storiesOf } from '@storybook/react';
import * as React from 'react';
import { useResetState } from '../src';
import ShowDocs from './util/ShowDocs';

const Demo = () => {
const [state, setState, resetState] = useResetState({
foo: '',
count: 0,
});

return (
<div>
<pre>{JSON.stringify(state, null, 2)}</pre>
<button onClick={(prev) => setState((prev) => ({ foo: 'bar', count: prev.count + 1 }))}>
set bar and count ++
</button>
<button onClick={() => resetState()}>resetState</button>
</div>
);
};

storiesOf('State/useResetState', module)
.add('Docs', () => <ShowDocs md={require('../docs/useResetState.md')} />)
.add('Demo', () => <Demo />);
102 changes: 102 additions & 0 deletions tests/useResetState.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { act, renderHook } from '@testing-library/react-hooks';
import useResetState from '../src/useResetState';

describe('useResetState', () => {
const setUp = <S>(initialState: S) =>
renderHook(() => {
const [state, setState, resetState] = useResetState<S>(initialState);

return {
state,
setState,
resetState,
} as const;
});

it('should support initialValue', () => {
const hook = setUp({ foo: 'bar' });
expect(hook.result.current.state).toEqual({ foo: 'bar' });
});

it('should reset state', () => {
const hook = setUp({
foo: 'bar',
count: 0,
});

act(() => {
hook.result.current.setState({
foo: 'foo',
count: 1,
});
});

act(() => {
hook.result.current.resetState();
});

expect(hook.result.current.state).toEqual({ foo: 'bar', count: 0 });
});

it('should support function update', () => {
const hook = setUp({
count: 0,
});

act(() => {
hook.result.current.setState((prev) => ({ count: prev.count + 1 }));
});

expect(hook.result.current.state).toEqual({ count: 1 });

act(() => {
hook.result.current.resetState();
});

expect(hook.result.current.state).toEqual({ count: 0 });
});

it('should reset state asynchronously', async () => {
const hook = setUp({
foo: 'bar',
count: 1,
});

await act(async () => {
hook.result.current.setState({
foo: 'foo',
count: 2,
});
});

await act(async () => {
await hook.result.current.resetState();
});

expect(hook.result.current.state).toEqual({ foo: 'bar', count: 1 });
});

it('should return undefined when resetState is called', () => {
const hook = setUp({
foo: 'bar',
});

const returnValue = hook.result.current.resetState();

expect(returnValue).toBeUndefined();
});

it('should correctly update state', () => {
const hook = setUp({
count: 0,
});

act(() => {
hook.result.current.setState({
count: 5,
});
});

expect(hook.result.current.state).toEqual({ count: 5 });
});
});