mirror of
https://github.com/reactjs/react.dev.git
synced 2026-02-22 03:42:14 +00:00
Hooks FAQ: Change usePrevious recommendation (#4780)
* Hook FAQ: Change usePrevious recommendation * typo
This commit is contained in:
@@ -331,54 +331,22 @@ This is a rare use case. If you need it, you can [use a mutable ref](#is-there-s
|
||||
|
||||
### How to get the previous props or state? {#how-to-get-the-previous-props-or-state}
|
||||
|
||||
Currently, you can do it manually [with a ref](#is-there-something-like-instance-variables):
|
||||
There are two cases in which you might want to get previous props or state.
|
||||
|
||||
```js{6,8}
|
||||
function Counter() {
|
||||
const [count, setCount] = useState(0);
|
||||
Sometimes, you need previous props to **clean up an effect.** For example, you might have an effect that subscribes to a socket based on the `userId` prop. If the `userId` prop changes, you want to unsubscribe from the _previous_ `userId` and subscribe to the _next_ one. You don't need to do anything special for this to work:
|
||||
|
||||
const prevCountRef = useRef();
|
||||
useEffect(() => {
|
||||
prevCountRef.current = count;
|
||||
});
|
||||
const prevCount = prevCountRef.current;
|
||||
|
||||
return <h1>Now: {count}, before: {prevCount}</h1>;
|
||||
}
|
||||
```js
|
||||
useEffect(() => {
|
||||
ChatAPI.subscribeToSocket(props.userId);
|
||||
return () => ChatAPI.unsubscribeFromSocket(props.userId);
|
||||
}, [props.userId]);
|
||||
```
|
||||
|
||||
This might be a bit convoluted but you can extract it into a custom Hook:
|
||||
In the above example, if `userId` changes from `3` to `4`, `ChatAPI.unsubscribeFromSocket(3)` will run first, and then `ChatAPI.subscribeToSocket(4)` will run. There is no need to get "previous" `userId` because the cleanup function will capture it in a closure.
|
||||
|
||||
```js{3,7}
|
||||
function Counter() {
|
||||
const [count, setCount] = useState(0);
|
||||
const prevCount = usePrevious(count);
|
||||
return <h1>Now: {count}, before: {prevCount}</h1>;
|
||||
}
|
||||
Other times, you might need to **adjust state based on a change in props or other state**. This is rarely needed and is usually a sign you have some duplicate or redundant state. However, in the rare case that you need this pattern, you can [store previous state or props in state and update them during rendering](#how-do-i-implement-getderivedstatefromprops).
|
||||
|
||||
function usePrevious(value) {
|
||||
const ref = useRef();
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
return ref.current;
|
||||
}
|
||||
```
|
||||
|
||||
Note how this would work for props, state, or any other calculated value.
|
||||
|
||||
```js{5}
|
||||
function Counter() {
|
||||
const [count, setCount] = useState(0);
|
||||
|
||||
const calculation = count + 100;
|
||||
const prevCalculation = usePrevious(calculation);
|
||||
// ...
|
||||
```
|
||||
|
||||
It's possible that in the future React will provide a `usePrevious` Hook out of the box since it's a relatively common use case.
|
||||
|
||||
See also [the recommended pattern for derived state](#how-do-i-implement-getderivedstatefromprops).
|
||||
We have previously suggested a custom Hook called `usePrevious` to hold the previous value. However, we've found that most use cases fall into the two patterns described above. If your use case is different, you can [hold a value in a ref](#is-there-something-like-instance-variables) and manually update it when needed. Avoid reading and updating refs during rendering because this makes your component's behavior difficult to predict and understand.
|
||||
|
||||
### Why am I seeing stale props or state inside my function? {#why-am-i-seeing-stale-props-or-state-inside-my-function}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user