use-controllable-state 🎮🔄
Hey Control Freak (in a good way!) 😉
The use-controllable-state
hook is a super useful utility for creating components that can have both controlled (state managed by parent via props) and uncontrolled (internal state, with a default initial value) behavior for a piece of their state.
It's like giving your component a dual-mode switch 🕹️: let the parent drive, or drive itself!
The Pattern:
Many native HTML elements work this way (e.g., <input type="text">
can have value
and onChange
for controlled, or just defaultValue
for uncontrolled).
This hook makes it easy to replicate that flexibility in your own components.
How it Works:
You provide the hook with:
prop
: The controlled value from props (e.g.,props.value
).defaultProp
: The default uncontrolled value (e.g.,props.defaultValue
).onChange
: A callback to notify the parent when the value changes (used in controlled mode).
The hook then returns [state, setState]
, where state
is the current value (either from props or internal) and setState
is a function to update it (which also calls onChange
if controlled).
Basic Usage:
import { useControllableState } from '@ryvora/react-use-controllable-state';
import React from 'react';
interface MyInputProps {
value?: string;
defaultValue?: string;
onChange?: (value: string) => void;
}
function MyInput({ value: valueProp, defaultValue, onChange }: MyInputProps) {
const [value, setValue] = useControllableState({
prop: valueProp,
defaultProp: defaultValue ?? '',
onChange,
caller: 'MyInput', // Optional: for better debug messages
});
return <input type="text" value={value} onChange={(e) => setValue(e.target.value)} />;
}
// Usage:
// <MyInput onChange={...} value={controlledValue} />
// <MyInput defaultValue="I am uncontrolled!" />
Build flexible and predictable components with controllable state! 🌟💪