@primer/react
Version:
An implementation of GitHub's Primer Design System using React
38 lines (37 loc) • 2.4 kB
JavaScript
import { warning } from "../utils/warning.js";
import React from "react";
//#region src/hooks/useControllableState.ts
/**
* This custom hook simplifies the behavior of a component if it has state that
* can be both controlled and uncontrolled. It functions identical to a
* useState() hook and provides [state, setState] for you to use. You can use
* the `onChange` argument to allow updates to the `state` to be communicated to
* owners of controlled components.
*
* Note: This hook will warn if a component is switching from controlled to
* uncontrolled, or vice-versa.
*/
function useControllableState({ name = "custom", defaultValue, value, onChange }) {
const [state, internalSetState] = React.useState(value !== null && value !== void 0 ? value : defaultValue);
const controlled = React.useRef(null);
const stableOnChange = React.useRef(onChange);
React.useEffect(() => {
stableOnChange.current = onChange;
});
if (controlled.current === null) controlled.current = value !== void 0;
const setState = React.useCallback((stateOrUpdater) => {
var _stableOnChange$curre;
const value_0 = typeof stateOrUpdater === "function" ? stateOrUpdater(state) : stateOrUpdater;
if (controlled.current === false) internalSetState(value_0);
(_stableOnChange$curre = stableOnChange.current) === null || _stableOnChange$curre === void 0 || _stableOnChange$curre.call(stableOnChange, value_0);
}, [state]);
React.useEffect(() => {
const controlledValue = value !== void 0;
if (controlled.current === false && controlledValue) warning(true, "A component is changing an uncontrolled %s 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", name);
if (controlled.current === true && !controlledValue) warning(true, "A component is changing a controlled %s 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);
}, [name, value]);
if (controlled.current === true) return [value, setState];
return [state, setState];
}
//#endregion
export { useControllableState };