Created
August 6, 2021 16:24
-
-
Save nfarina/b733842e1541008634541b0503c882b4 to your computer and use it in GitHub Desktop.
A version of React's `useState` that resets the value to initial whenever the given dependency array changes. Very helpful when you need to reset some internal state as the result of getting new props.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { DependencyList, Dispatch, SetStateAction, useState } from "react"; | |
/** | |
* This is like useState() but with the added feature of returning the initial | |
* value whenever the dependency list changes. This is super useful for allowing | |
* components to "reset" some internal state as a result of getting new props. | |
*/ | |
export function useResettableState<S>( | |
initial: S | (() => S), | |
deps: DependencyList, | |
): [S, Dispatch<SetStateAction<S>>] { | |
const [innerValue, setInnerValue] = useState(initial); | |
const [prevDeps, setPrevDeps] = useState(deps); | |
// If the deps changed, reset our state to initial. | |
// Calling setState during render is rare but supported! | |
// https://github.com/facebook/react/issues/14738#issuecomment-461868904 | |
if (depsChanged(deps, prevDeps)) { | |
setPrevDeps(deps); | |
setInnerValue(initial); | |
} | |
return [innerValue, setInnerValue]; | |
} | |
function depsChanged( | |
previous: DependencyList | undefined, | |
current: DependencyList | undefined, | |
): boolean { | |
if (previous === undefined && current === undefined) return false; | |
if (previous === undefined || current === undefined) return true; | |
if (previous.length !== current.length) { | |
console.error( | |
"useResettableState(): Dependency array size changed between renders!", | |
); | |
return false; | |
} | |
// Lengths are the same; must compare values. | |
for (let i = 0; i < previous.length; i += 1) { | |
if (previous[i] !== current[i]) { | |
return true; | |
} | |
} | |
// Unchanged! | |
return false; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment