Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import { useState, useEffect, useRef } from 'react';
// Usage
function App() {
// State value and setter for our example
const [count, setCount] = useState(0);
// Get the previous value (was passed into hook on last render)
const prevCount = usePrevious(count);
// Display both current and previous count value
return (
<div>
<h1>Now: {count}, before: {prevCount}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// Hook
function usePrevious(value) {
// The ref object is a generic container whose current property is mutable ...
// ... and can hold any value, similar to an instance property on a class
const ref = useRef();
// Store current value in ref
useEffect(() => {
ref.current = value;
}, [value]); // Only re-run if value changes
// Return previous value (happens before update in useEffect above)
return ref.current;
}
@ianobermiller

This comment has been minimized.

Copy link

commented Nov 9, 2018

Love all the comments in the custom hook function!

@ritwickdey

This comment has been minimized.

Copy link

commented Nov 14, 2018

Just an optimization, not sooooo inportant

useEffect(() => {
    ref.current = value;
  }, [value]); // only run if and only if value is changed
@gragland

This comment has been minimized.

Copy link
Owner Author

commented Nov 20, 2018

@ritwickdey Thanks, code updated!

@olee

This comment has been minimized.

Copy link

commented Dec 30, 2018

I wrote the following alternative which (even if it looks a bit complicated) can get around with just a single useState and should increase performance a lot because it does not need to check if the effect needs to run on every render.

import { useState, Dispatch, SetStateAction } from 'react';

type SetStateFn<T> = (previousValue: T) => T;

type IValueWrapper<T> = [
    /** value */
    T,
    /** setValue */
    Dispatch<SetStateAction<T>>,
    /** previousValue */
    T | undefined
];

/**
 * Drop-in replacement for react useState which also returns previousValue.
 * @return [value, setValue, previousValue]
 */
export default function useStateWithPrevious<T>(initialValue: T) {
    const createSetStateDispatch: (previousValue: T) => Dispatch<SetStateAction<T>> = previousValue => value => {
        const newValue = typeof value === 'function' ? (value as SetStateFn<T>)(previousValue) : value;
        setValueWrapper([
            newValue,
            createSetStateDispatch(newValue),
            previousValue,
        ]);
    };
    const [valueWrapper, setValueWrapper] = useState<IValueWrapper<T>>(() => [
        initialValue,
        createSetStateDispatch(initialValue),
        undefined,
    ]);
    return valueWrapper;
}
@thebiltheory

This comment has been minimized.

Copy link

commented Jun 11, 2019

Clean up

function usePrevious(value) {
  // The ref object is a generic container whose current property is mutable ...
  // ... and can hold any value, similar to an instance property on a class
  const ref = useRef();
  
  // Store current value in ref
  useEffect(() => {
    ref.current = value;
    // Clean Up
    return () => {
          ref.current = null;
    }
  }, [value]); // Only re-run if value changes

(cc @AmaanKulshreshtha )

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.