Skip to content

Instantly share code, notes, and snippets.

@devhammed
Last active November 27, 2025 07:32
Show Gist options
  • Select an option

  • Save devhammed/f0145624910849bd5722548ee9d4192f to your computer and use it in GitHub Desktop.

Select an option

Save devhammed/f0145624910849bd5722548ee9d4192f to your computer and use it in GitHub Desktop.
Use Controlled State hook manages a value that can be either controlled or uncontrolled. It returns the current state and a setter that updates internal state when uncontrolled and always calls an optional onChange callback.
import { useCallback, useState } from 'react';
export function useControlledState<T>(
controlledValue: T | undefined,
initialValue: T,
onChange?: (value: T) => void,
): [T, (value: T | ((prev: T) => T)) => void] {
const [internalState, setInternalState] = useState(initialValue);
const isControlled = controlledValue !== undefined;
const state = isControlled ? controlledValue : internalState;
const setState = useCallback(
(value: T | ((prev: T) => T)) => {
const next = typeof value === 'function' ? (value as (prev: T) => T)(state) : value;
if (!isControlled) {
setInternalState(next);
}
onChange?.(next);
},
[isControlled, onChange, state, setInternalState],
);
return [state, setState];
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment