UNPKG

@primer/react

Version:

An implementation of GitHub's Primer Design System using React

67 lines (59 loc) 3.17 kB
'use strict'; var React = require('react'); var warning = require('../utils/warning.js'); function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; } var React__default = /*#__PURE__*/_interopDefault(React); /** * 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__default.default.useState(value !== null && value !== void 0 ? value : defaultValue); const controlled = React__default.default.useRef(null); const stableOnChange = React__default.default.useRef(onChange); React__default.default.useEffect(() => { stableOnChange.current = onChange; }); if (controlled.current === null) { controlled.current = value !== undefined; } const setState = React__default.default.useCallback(stateOrUpdater => { var _stableOnChange$curre; const value_0 = typeof stateOrUpdater === 'function' ? // @ts-ignore stateOrUpdater is a function stateOrUpdater(state) : stateOrUpdater; if (controlled.current === false) { internalSetState(value_0); } (_stableOnChange$curre = stableOnChange.current) === null || _stableOnChange$curre === void 0 ? void 0 : _stableOnChange$curre.call(stableOnChange, value_0); }, [state]); React__default.default.useEffect(() => { const controlledValue = value !== undefined; // Uncontrolled -> Controlled // If the component prop is uncontrolled, the prop value should be undefined if (controlled.current === false && controlledValue) { process.env.NODE_ENV !== "production" ? warning.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) : void 0; } // Controlled -> Uncontrolled // If the component prop is controlled, the prop value should be defined if (controlled.current === true && !controlledValue) { process.env.NODE_ENV !== "production" ? warning.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) : void 0; } }, [name, value]); if (controlled.current === true) { return [value, setState]; } return [state, setState]; } exports.useControllableState = useControllableState;