uncontrollable
Version:
Wrap a controlled react component, to allow specific prop/handler pairs to be uncontrolled
42 lines (41 loc) • 1.37 kB
JavaScript
import { useCallback, useRef, useState } from 'react';
export function defaultKey(key) {
return 'default' + key.charAt(0).toUpperCase() + key.substr(1);
}
function useUncontrolledProp(propValue, defaultValue, handler) {
const wasPropRef = useRef(propValue !== undefined);
const [stateValue, setState] = useState(defaultValue);
const isProp = propValue !== undefined;
const wasProp = wasPropRef.current;
wasPropRef.current = isProp;
/**
* If a prop switches from controlled to Uncontrolled
* reset its value to the defaultValue
*/
if (!isProp && wasProp && stateValue !== defaultValue) {
setState(defaultValue);
}
return [isProp ? propValue : stateValue, useCallback((...args) => {
const [value, ...rest] = args;
let returnValue = handler?.(value, ...rest);
setState(value);
return returnValue;
}, [handler])];
}
export { useUncontrolledProp };
export function useUncontrolled(props, config) {
return Object.keys(config).reduce((result, fieldName) => {
const {
[defaultKey(fieldName)]: defaultValue,
[fieldName]: propsValue,
...rest
} = result;
const handlerName = config[fieldName];
const [value, handler] = useUncontrolledProp(propsValue, defaultValue, props[handlerName]);
return {
...rest,
[fieldName]: value,
[handlerName]: handler
};
}, props);
}