-
-
Save gragland/1ed713a68c770ea414c3b92ccf2bdd2f to your computer and use it in GitHub Desktop.
| 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; | |
| } |
A better version with support for initialValue. Backward compatible with previous version.
function usePrevious<T>(value: T, initialValue?: T): T {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}hmmm why would you need an initialValue for a usePrevious? it was undefined previously.
This seems to handle all the cases discussed in this thread*:
function usePrevious(value){
const ref = useRef();
useEffect(
() => { ref.current = value; },
[value]
);
return ref.current;
}* except for initialValue
hmmm why would you need an initialValue for a usePrevious? it was undefined previously.
I have a side effect which calls an API if the current value changes and is different from the previous value. Without initial value, the change is always triggered after first render.
@manzoorwanijk can you give some example code?
…are you doing something like?:
function Image({ src, ...props }){
const prevSrc = usePrevious(src)
useEffect(
()=> {
console.log(`src changed`, {to: src, was: prevSrc})
},
[src]
)
return <img {...props} src={src}/>
}export default function usePrevious(value) {
// ref value will always be like [prev, state]
let ref = useRef([null, null]);
// storing prev, state values
ref.current.shift()
ref.current.push(value)
// Return previous value
return ref.current[0];
}@manikanta-kotha it seems like this could be simpler and work the same:
export default function usePrevious(value) {
const ref = useRef();
const prev = ref.current
ref.current = value
return prev;
}…but it might be nice to always return the previous value. Even on subsequent renders. Like this:
export default function usePrevious(value) {
const ref = useRef();
if (ref.current !== value){
ref.previous = ref.current
ref.current = value
}
return ref.previous;
}
Because technically it had no previous value on the first render and you may need to know that in your components.