UNPKG

@carbon/react

Version:

React components for the Carbon Design System

52 lines (50 loc) 2.43 kB
/** * Copyright IBM Corp. 2016, 2026 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ import { warning } from "./warning.js"; import { useEffect, useRef, useState } from "react"; //#region src/internal/useControllableState.ts /** * Copyright IBM Corp. 2016, 2025 * * This source code is licensed under the Apache-2.0 license found in the * LICENSE file in the root directory of this source tree. */ /** * This hook simplifies the behavior of a component that has state which can be * both controlled and uncontrolled. It works like `useState`. You can use the * `onChange` callback to communicate state updates to parent components. * * Note: This hook will warn if the component switches between controlled and * uncontrolled states. */ const useControllableState = ({ defaultValue, name = "custom", onChange, value }) => { const [state, internalSetState] = useState(typeof value !== "undefined" ? value : defaultValue); const controlled = useRef(null); if (controlled.current === null) controlled.current = typeof value !== "undefined"; const setState = (stateOrUpdater) => { const newValue = typeof stateOrUpdater === "function" ? stateOrUpdater(state) : stateOrUpdater; if (controlled.current === false) internalSetState(newValue); if (onChange) onChange(newValue); }; useEffect(() => { const controlledValue = typeof value !== "undefined"; if (controlled.current === false && controlledValue) warning(false, `A component is changing an uncontrolled ${name} component to be controlled. This is likely caused by the value changing to a defined value from undefined. Decide between using a controlled or uncontrolled value for the lifetime of the component. More info: https://reactjs.org/link/controlled-components`); if (controlled.current === true && !controlledValue) warning(false, `A component is changing a controlled ${name} component to be uncontrolled. This is likely caused by the value changing to an undefined value from a defined one. Decide between using a controlled or uncontrolled value for the lifetime of the component. More info: https://reactjs.org/link/controlled-components`); }, [name, value]); if (controlled.current === true) return [ value, setState, controlled.current ]; return [ state, setState, controlled.current ]; }; //#endregion export { useControllableState };