Skip to main content

useControllableState

A custom hook for managing both controlled and uncontrolled state.

If value is provided, it operates in controlled mode; if not provided, it operates in uncontrolled mode.

  • In controlled mode, value is managed externally, and the setValue function returned by this hook cannot change the internal value.

  • In uncontrolled mode, defaultValue is used as the initial value, and the setValue function returned by this hook can change the internal value.


Code

🔗 View source code


Interface

typescript
interface UseControllableStateOptions<T> {
value?: T | undefined;
defaultValue: T;
}
typescript
function useControllableState<T>({
value,
defaultValue,
}: UseControllableStateOptions<T>): [T, (nextValue: SetStateAction<T>) => void];

Options

NameTypeDefaultDescription
valueT | undefinedundefinedThe external state value for controlled mode. When provided, the hook operates in controlled mode.
defaultValueT-The initial value for uncontrolled mode.

Remarks

Primary Use Cases

This hook is ideal for managing the checked state of elements like checkbox and radio in a controlled/uncontrolled split.

  • Provide value via props for controlled mode; omit it for uncontrolled mode.

Usage

Uncontrolled Mode

  • When value is not provided or is undefined, the hook operates in uncontrolled mode.
  • defaultValue is used as the initial value, and the value can be changed via setValue.
typescript
import { useControllableState } from '@modern-kit/react';

const UncontrolledExample = () => {
const [value, setValue] = useControllableState({ defaultValue: 0 });

return (
<div>
<p>Current value: {value}</p>
<button onClick={() => setValue((prev) => (prev ?? 0) + 1)}>
Increment
</button>
<button onClick={() => setValue(0)}>Reset</button>
</div>
);
};

Controlled Mode

  • When value is provided, the hook operates in controlled mode.
  • The state is managed externally and cannot be changed via the setValue returned from useControllableState.
typescript
import { useState } from 'react';
import { useControllableState } from '@modern-kit/react';

const ControlledExample = () => {
const [externalValue, setExternalValue] = useState(10);
const [value, setValue] = useControllableState({ value: externalValue, defaultValue: 0 });

return (
<div>
<p>Current value: {value}</p>
<button onClick={() => setValue((prev) => (prev ?? 0) + 1)}>
Increment internally (does not work)
</button>
<button onClick={() => setExternalValue((prev) => prev + 1)}>
Increment externally (works)
</button>
</div>
);
};

Example

Uncontrolled Mode

Uncontrolled mode - Current value: 0

Controlled Mode

Controlled mode - Current value: 10