138 lines
4.1 KiB
JavaScript
138 lines
4.1 KiB
JavaScript
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 = ({
|
|
name,
|
|
initialValues,
|
|
fields,
|
|
form,
|
|
preserve,
|
|
children,
|
|
component: Component = 'form',
|
|
validateMessages,
|
|
validateTrigger = 'onChange',
|
|
onValuesChange,
|
|
onFieldsChange,
|
|
onFinish,
|
|
onFinishFailed,
|
|
clearOnDestroy,
|
|
...restProps
|
|
}, ref) => {
|
|
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; |