mirror of
https://github.com/streamich/react-use.git
synced 2026-01-18 14:06:52 +00:00
Merge pull request #1203 from ClementParis016/pr/use-latest
feat: add useLatest hook
This commit is contained in:
commit
56c2c93bf4
@ -131,6 +131,7 @@
|
||||
- [`useDefault`](./docs/useDefault.md) — returns the default value when state is `null` or `undefined`.
|
||||
- [`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.
|
||||
- [`useLatest`](./docs/useLatest.md) — returns the latest state or props
|
||||
- [`usePrevious`](./docs/usePrevious.md) — returns the previous state or props. [![][img-demo]](https://codesandbox.io/s/fervent-galileo-krgx6)
|
||||
- [`usePreviousDistinct`](./docs/usePreviousDistinct.md) — like `usePrevious` but with a predicate to determine if `previous` should update.
|
||||
- [`useObservable`](./docs/useObservable.md) — tracks latest value of an `Observable`.
|
||||
|
||||
36
docs/useLatest.md
Normal file
36
docs/useLatest.md
Normal file
@ -0,0 +1,36 @@
|
||||
# `useLatest`
|
||||
|
||||
React state hook that returns the latest state as described in the [React hooks FAQ](https://reactjs.org/docs/hooks-faq.html#why-am-i-seeing-stale-props-or-state-inside-my-function).
|
||||
|
||||
This is mostly useful to get access to the latest value of some props or state inside an asynchronous callback, instead of that value at the time the callback was created from.
|
||||
|
||||
## Usage
|
||||
|
||||
```jsx
|
||||
import { useLatest } from 'react-use';
|
||||
|
||||
const Demo = () => {
|
||||
const [count, setCount] = React.useState(0);
|
||||
const latestCount = useLatest(count);
|
||||
|
||||
function handleAlertClick() {
|
||||
setTimeout(() => {
|
||||
alert(`Latest count value: ${latestCount.current}`);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>You clicked {count} times</p>
|
||||
<button onClick={() => setCount(count + 1)}>Click me</button>
|
||||
<button onClick={handleAlertClick}>Show alert</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
```ts
|
||||
const latestState = useLatest = <T>(state: T): MutableRefObject<T>;
|
||||
```
|
||||
@ -42,6 +42,7 @@ export { default as createBreakpoint } from './createBreakpoint';
|
||||
// export { default as useKeyboardJs } from './useKeyboardJs';
|
||||
export { default as useKeyPress } from './useKeyPress';
|
||||
export { default as useKeyPressEvent } from './useKeyPressEvent';
|
||||
export { default as useLatest } from './useLatest';
|
||||
export { default as useLifecycles } from './useLifecycles';
|
||||
export { default as useList } from './useList';
|
||||
export { default as useLocalStorage } from './useLocalStorage';
|
||||
@ -111,4 +112,4 @@ export { useRendersCount } from './useRendersCount';
|
||||
export { useFirstMountState } from './useFirstMountState';
|
||||
export { default as useSet } from './useSet';
|
||||
export { createGlobalState } from './createGlobalState';
|
||||
export { useHash } from './useHash'
|
||||
export { useHash } from './useHash';
|
||||
|
||||
28
stories/useLatest.story.tsx
Normal file
28
stories/useLatest.story.tsx
Normal file
@ -0,0 +1,28 @@
|
||||
import { storiesOf } from '@storybook/react';
|
||||
import * as React from 'react';
|
||||
import { useLatest } from '../src';
|
||||
import ShowDocs from './util/ShowDocs';
|
||||
|
||||
const Demo = () => {
|
||||
const [count, setCount] = React.useState(0);
|
||||
const latestCount = useLatest(count);
|
||||
const timeoutMs = 3000;
|
||||
|
||||
function handleAlertClick() {
|
||||
setTimeout(() => {
|
||||
alert(`Latest count value: ${latestCount.current}`);
|
||||
}, timeoutMs);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<p>You clicked {count} times</p>
|
||||
<button onClick={() => setCount(count + 1)}>Click me</button>
|
||||
<button onClick={handleAlertClick}>Show alert in {timeoutMs / 1000}s</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
storiesOf('State|useLatest', module)
|
||||
.add('Docs', () => <ShowDocs md={require('../docs/useLatest.md')} />)
|
||||
.add('Demo', () => <Demo />);
|
||||
23
tests/useLatest.test.ts
Normal file
23
tests/useLatest.test.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { renderHook } from '@testing-library/react-hooks';
|
||||
import useLatest from '../src/useLatest';
|
||||
|
||||
const setUp = () => renderHook(({ state }) => useLatest(state), { initialProps: { state: 0 } });
|
||||
|
||||
it('should return a ref with the latest value on initial render', () => {
|
||||
const { result } = setUp();
|
||||
|
||||
expect(result.current).toEqual({ current: 0 });
|
||||
});
|
||||
|
||||
it('should always return a ref with the latest value after each update', () => {
|
||||
const { result, rerender } = setUp();
|
||||
|
||||
rerender({ state: 2 });
|
||||
expect(result.current).toEqual({ current: 2 });
|
||||
|
||||
rerender({ state: 4 });
|
||||
expect(result.current).toEqual({ current: 4 });
|
||||
|
||||
rerender({ state: 6 });
|
||||
expect(result.current).toEqual({ current: 6 });
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user