Skip to content

useControllableState

Category
Export Size
611 B
Last Changed
5 days ago

A hook for combining controlled and uncontrolled state sources.

Demo

Usage

tsx
import { 
useControllableState
} from '@reause/shared'
import {
useState
} from 'react'
// tuple state: `value` is the external value and `setValue` writes through to `setExternal` const [
external
,
setExternal
] =
useState
('controlled')
const [
value
,
setValue
] =
useControllableState
([
external
,
setExternal
])
// passive plain-value state: initialized from the source, local updates persist const [
draft
,
setDraft
] =
useControllableState
('draft', {
passive
: true })

Tuple [value, setter] and { value, onChange } sources are always controlled: the current value is the resolved source and setValue writes through to the tuple setter / onChange.

toValue resolution is applied on every render, so lazy getters, refs, tuples, and value objects are supported consistently.

Type Declarations

ts
export type StateTuple<T> = [
    T,
    Dispatch<SetStateAction<T>>
]

export type State<T> = StateValue<T>

export interface UseControllableStateOptions<T> {
    defaultValue?: T | (() => T);
    shouldUpdate?: (prev: T, next: T) => boolean;
    passive?: boolean;
}

export type StateValue<T> = T | (() => T) | readonly [
    T,
    (value: T | ((prev: T) => T)) => void
] | {
    value: T;
    onChange?: (value: T) => void;
}

export function useControllableState<T>(state: State<T>, options?: UseControllableStateOptions<T>): StateTuple<T>

export function toValue<T>(value: StateValue<T>): T

export function toValue<T>(value: StateValue<T> | undefined | null): T | undefined | null

export function writeState<T>(source: StateValue<T> | undefined | null, value: T): void

Source

Source · Demo

Contributors

hairyf

Changelog

v0.1.0 on
98671 - fix(shared): resolve useControllableState audit findings (#729)

Released under the MIT License. v0.1.8