# useControllableState

State for a component that can be controlled (the parent passes `value` and `onChange`) or uncontrolled (the parent passes only a default), like a native `<input>` with `value` or `defaultValue`.

Returns `[value, setValue]` like `useState`. `setValue` calls `onChange` only when the value actually changes, and accepts an updater function that sees the latest value, also for several calls in one event. Controlled while `value` is not `undefined`; don't switch between the two.

## Import

```ts
import { useControllableState } from '@vincent.ri/react-tils'
// or only this hook
import { useControllableState } from '@vincent.ri/react-tils/useControllableState'
```

## Usage

```ts
type Props = { open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void }
function Disclosure({ open: openProp, defaultOpen = false, onOpenChange }: Props) {
  const [open, setOpen] = useControllableState(openProp, defaultOpen, onOpenChange)
  return <button aria-expanded={open} onClick={() => setOpen((o) => !o)}>Details</button>
}
```

## When to use it

Building a reusable component (tabs, accordion, toggle, select, dialog `open`) whose parent may or may not want to own the state.

## When not to

The state is only used inside one component; use `useState`. Never copy a prop into state with `useState(prop)` + `useEffect` to sync it: the copy goes stale or flickers. Use this hook instead.

## API

```ts
function useControllableState<T>(value: T | undefined, defaultValue: T, onChange?: (value: T) => void): [T, SetValue<T>]
```

| Parameter | Description |
| --- | --- |
| `value` | The controlled value, or `undefined` when uncontrolled. |
| `defaultValue` | The starting value when uncontrolled. |
| `onChange` | Called with the new value on every change. Optional. |

## Browser support

Works in all modern browsers.

## Coming from another library?

Other libraries call this `useControlled`, `useUncontrolled`, `useControllableValue`.

---

204 B minified and brotlied
Source: https://github.com/vincentri/react-tils/blob/main/src/useControllableState.ts
Docs page: https://vincentri.github.io/react-tils/hooks/useControllableState/
Previous: [useBeforeUnload](https://vincentri.github.io/react-tils/hooks/useBeforeUnload.md)
Next: [useAnnounce](https://vincentri.github.io/react-tils/hooks/useAnnounce.md)
