MCPcopy Index your code
hub / github.com/primer/react / useControllableState

Function useControllableState

packages/react/src/hooks/useControllableState.ts:36–108  ·  view source on GitHub ↗
({
  name = 'custom',
  defaultValue,
  value,
  onChange,
}: ControllableStateOptions<T>)

Source from the content-addressed store, hash-verified

34 * uncontrolled, or vice-versa.
35 */
36export function useControllableState<T>({
37 name = 'custom',
38 defaultValue,
39 value,
40 onChange,
41}: ControllableStateOptions<T>): [T, React.Dispatch<React.SetStateAction<T>>] {
42 const [state, internalSetState] = React.useState(value ?? defaultValue)
43 const controlled = React.useRef<boolean | null>(null)
44 const stableOnChange = React.useRef(onChange)
45
46 React.useEffect(() => {
47 stableOnChange.current = onChange
48 })
49
50 if (controlled.current === null) {
51 controlled.current = value !== undefined
52 }
53
54 const setState = React.useCallback(
55 (stateOrUpdater: T | ((prevState: T) => T)) => {
56 const value =
57 typeof stateOrUpdater === 'function'
58 ? // @ts-ignore stateOrUpdater is a function
59 stateOrUpdater(state)
60 : stateOrUpdater
61
62 if (controlled.current === false) {
63 internalSetState(value)
64 }
65
66 stableOnChange.current?.(value)
67 },
68 [state],
69 )
70
71 React.useEffect(() => {
72 const controlledValue = value !== undefined
73
74 // Uncontrolled -> Controlled
75 // If the component prop is uncontrolled, the prop value should be undefined
76 if (controlled.current === false && controlledValue) {
77 warning(
78 true,
79 'A component is changing an uncontrolled %s component to be controlled. ' +
80 'This is likely caused by the value changing to a defined value ' +
81 'from undefined. Decide between using a controlled or uncontrolled ' +
82 'value for the lifetime of the component. ' +
83 'More info: https://reactjs.org/link/controlled-components',
84 name,
85 )
86 }
87
88 // Controlled -> Uncontrolled
89 // If the component prop is controlled, the prop value should be defined
90 if (controlled.current === true && !controlledValue) {
91 warning(
92 true,
93 'A component is changing a controlled %s component to be uncontrolled. ' +

Callers 2

TextInputFunction · 0.90
TreeView.tsxFile · 0.90

Calls

no outgoing calls

Tested by 1

TextInputFunction · 0.72