UNPKG

@rc-component/form

Version:
139 lines (129 loc) 4.3 kB
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import * as React from 'react'; import useForm from "./hooks/useForm"; import FieldContext, { HOOK_MARK } from "./FieldContext"; import FormContext from "./FormContext"; import { isSimilar } from "./utils/valueUtil"; import ListContext from "./ListContext"; const Form = (props, ref) => { const { name, initialValues, fields, form, preserve, children, component: Component = 'form', validateMessages, validateTrigger = 'onChange', onValuesChange, onFieldsChange, onFinish, onFinishFailed, clearOnDestroy, ...restProps } = props; const nativeElementRef = React.useRef(null); const formContext = React.useContext(FormContext); // We customize handle event since Context will makes all the consumer re-render: // https://reactjs.org/docs/context.html#contextprovider const [formInstance] = useForm(form); const { useSubscribe, setInitialValues, setCallbacks, setValidateMessages, setPreserve, destroyForm } = formInstance.getInternalHooks(HOOK_MARK); // Pass ref with form instance React.useImperativeHandle(ref, () => ({ ...formInstance, nativeElement: nativeElementRef.current })); // Register form into Context React.useEffect(() => { formContext.registerForm(name, formInstance); return () => { formContext.unregisterForm(name); }; }, [formContext, formInstance, name]); // Pass props to store setValidateMessages({ ...formContext.validateMessages, ...validateMessages }); setCallbacks({ onValuesChange, onFieldsChange: (changedFields, ...rest) => { formContext.triggerFormChange(name, changedFields); if (onFieldsChange) { onFieldsChange(changedFields, ...rest); } }, onFinish: values => { formContext.triggerFormFinish(name, values); if (onFinish) { onFinish(values); } }, onFinishFailed }); setPreserve(preserve); // Set initial value, init store value when first mount const mountRef = React.useRef(null); setInitialValues(initialValues, !mountRef.current); if (!mountRef.current) { mountRef.current = true; } // ========================== Unmount =========================== React.useEffect(() => () => destroyForm(clearOnDestroy), // eslint-disable-next-line react-hooks/exhaustive-deps []); // Prepare children by `children` type let childrenNode; const childrenRenderProps = typeof children === 'function'; if (childrenRenderProps) { const values = formInstance.getFieldsValue(true); childrenNode = children(values, formInstance); } else { childrenNode = children; } // Not use subscribe when using render props useSubscribe(!childrenRenderProps); // Listen if fields provided. We use ref to save prev data here to avoid additional render const prevFieldsRef = React.useRef(null); React.useEffect(() => { if (!isSimilar(prevFieldsRef.current || [], fields || [])) { formInstance.setFields(fields || []); } prevFieldsRef.current = fields; }, [fields, formInstance]); // =========================== Render =========================== const formContextValue = React.useMemo(() => ({ ...formInstance, validateTrigger }), [formInstance, validateTrigger]); const wrapperNode = /*#__PURE__*/React.createElement(ListContext.Provider, { value: null }, /*#__PURE__*/React.createElement(FieldContext.Provider, { value: formContextValue }, childrenNode)); if (Component === false) { return wrapperNode; } return /*#__PURE__*/React.createElement(Component, _extends({}, restProps, { ref: nativeElementRef, onSubmit: event => { event.preventDefault(); event.stopPropagation(); formInstance.submit(); }, onReset: event => { event.preventDefault(); formInstance.resetFields(); restProps.onReset?.(event); } }), wrapperNode); }; export default Form;