diff --git a/src/client/components/elements/DuplicateDocument/index.js b/src/client/components/elements/DuplicateDocument/index.js
index 40c27aafba..6a1ed11b65 100644
--- a/src/client/components/elements/DuplicateDocument/index.js
+++ b/src/client/components/elements/DuplicateDocument/index.js
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { useHistory } from 'react-router-dom';
import config from 'payload/config';
import Button from '../Button';
-import useForm from '../../forms/Form/useForm';
+import { useForm } from '../../forms/Form/context';
import './index.scss';
diff --git a/src/client/components/elements/PreviewButton/index.js b/src/client/components/elements/PreviewButton/index.js
index 8c2c8f3701..3a444dd82b 100644
--- a/src/client/components/elements/PreviewButton/index.js
+++ b/src/client/components/elements/PreviewButton/index.js
@@ -1,6 +1,6 @@
import React from 'react';
import PropTypes from 'prop-types';
-import useForm from '../../forms/Form/useForm';
+import { useForm } from '../../forms/Form/context';
import { useUser } from '../../data/User';
import Button from '../Button';
diff --git a/src/client/components/forms/Form/FieldContext.js b/src/client/components/forms/Form/FieldContext.js
deleted file mode 100644
index 7c0127fbd6..0000000000
--- a/src/client/components/forms/Form/FieldContext.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { createContext } from 'react';
-
-export default createContext({});
diff --git a/src/client/components/forms/Form/FormContext.js b/src/client/components/forms/Form/FormContext.js
deleted file mode 100644
index 7c0127fbd6..0000000000
--- a/src/client/components/forms/Form/FormContext.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { createContext } from 'react';
-
-export default createContext({});
diff --git a/src/client/components/forms/Form/context.js b/src/client/components/forms/Form/context.js
new file mode 100644
index 0000000000..efacd8df45
--- /dev/null
+++ b/src/client/components/forms/Form/context.js
@@ -0,0 +1,26 @@
+import { createContext, useContext } from 'react';
+
+const FormContext = createContext({});
+const FieldContext = createContext({});
+const SubmittedContext = createContext(false);
+const ProcessingContext = createContext(false);
+const ModifiedContext = createContext(false);
+
+const useForm = () => useContext(FormContext);
+const useFormFields = () => useContext(FieldContext);
+const useFormSubmitted = () => useContext(SubmittedContext);
+const useFormProcessing = () => useContext(ProcessingContext);
+const useFormModified = () => useContext(ModifiedContext);
+
+export {
+ FormContext,
+ FieldContext,
+ SubmittedContext,
+ ProcessingContext,
+ ModifiedContext,
+ useForm,
+ useFormFields,
+ useFormSubmitted,
+ useFormProcessing,
+ useFormModified,
+};
diff --git a/src/client/components/forms/Form/index.js b/src/client/components/forms/Form/index.js
index 36846885ad..a4cba6417a 100644
--- a/src/client/components/forms/Form/index.js
+++ b/src/client/components/forms/Form/index.js
@@ -1,13 +1,11 @@
import React, {
- useReducer, useEffect, useRef,
+ useReducer, useEffect, useRef, useState,
} from 'react';
import { objectToFormData } from 'object-to-formdata';
import { useHistory } from 'react-router-dom';
import PropTypes from 'prop-types';
import { unflatten } from 'flatley';
import HiddenInput from '../field-types/HiddenInput';
-import FormContext from './FormContext';
-import FieldContext from './FieldContext';
import { useLocale } from '../../utilities/Locale';
import { useStatusList } from '../../elements/Status';
import { requests } from '../../../api';
@@ -16,6 +14,8 @@ import { useUser } from '../../data/User';
import fieldReducer from './fieldReducer';
import initContextState from './initContextState';
+import { SubmittedContext, ProcessingContext, ModifiedContext, FormContext, FieldContext } from './context';
+
import './index.scss';
const baseClass = 'form';
@@ -43,7 +43,7 @@ const Form = (props) => {
ajax,
method,
action,
- handleAjaxResponse,
+ handleResponse,
onSuccess,
children,
className,
@@ -56,6 +56,10 @@ const Form = (props) => {
const { replaceStatus, addStatus, clearStatus } = useStatusList();
const { refreshCookie } = useUser();
+ const [modified, setModified] = useState(false);
+ const [processing, setProcessing] = useState(false);
+ const [submitted, setSubmitted] = useState(false);
+
const contextRef = useRef({ ...initContextState });
const [fields, dispatchFields] = useReducer(fieldReducer, {});
@@ -69,7 +73,7 @@ const Form = (props) => {
}
e.stopPropagation();
- contextRef.current.setSubmitted(true);
+ setSubmitted(true);
const isValid = contextRef.current.validateForm();
@@ -106,17 +110,17 @@ const Form = (props) => {
});
const formData = contextRef.current.createFormData();
- contextRef.current.setProcessing(true);
+ setProcessing(true);
// Make the API call from the action
return requests[method.toLowerCase()](action, {
body: formData,
}).then((res) => {
- contextRef.current.setModified(false);
- if (typeof handleAjaxResponse === 'function') return handleAjaxResponse(res);
+ setModified(false);
+ if (typeof handleResponse === 'function') return handleResponse(res);
return res.json().then((json) => {
- contextRef.current.setProcessing(false);
+ setProcessing(false);
clearStatus();
if (res.status < 400) {
@@ -144,9 +148,7 @@ const Form = (props) => {
}
if (Array.isArray(json.errors)) {
- const [fieldErrors, nonFieldErrors] = json.errors.reduce(([fieldErrs, nonFieldErrs], err) => {
- return err.field && err.message ? [[...fieldErrs, err], nonFieldErrs] : [fieldErrs, [...nonFieldErrs, err]];
- }, [[], []]);
+ const [fieldErrors, nonFieldErrors] = json.errors.reduce(([fieldErrs, nonFieldErrs], err) => (err.field && err.message ? [[...fieldErrs, err], nonFieldErrs] : [fieldErrs, [...nonFieldErrs, err]]), [[], []]);
fieldErrors.forEach((err) => {
dispatchFields({
@@ -193,17 +195,11 @@ const Form = (props) => {
return true;
};
- contextRef.current.getFields = () => {
- return contextRef.current.fields;
- };
+ contextRef.current.getFields = () => contextRef.current.fields;
- contextRef.current.getField = (path) => {
- return contextRef.current.fields[path];
- };
+ contextRef.current.getField = (path) => contextRef.current.fields[path];
- contextRef.current.getData = () => {
- return reduceFieldsToValues(contextRef.current.fields, true);
- };
+ contextRef.current.getData = () => reduceFieldsToValues(contextRef.current.fields, true);
contextRef.current.getSiblingData = (path) => {
let siblingFields = contextRef.current.fields;
@@ -247,40 +243,26 @@ const Form = (props) => {
return unflattenedData?.[name];
};
- contextRef.current.getUnflattenedValues = () => {
- return reduceFieldsToValues(contextRef.current.fields);
- };
+ contextRef.current.getUnflattenedValues = () => reduceFieldsToValues(contextRef.current.fields);
- contextRef.current.validateForm = () => {
- return !Object.values(contextRef.current.fields).some((field) => {
- return field.valid === false;
- });
- };
+ contextRef.current.validateForm = () => !Object.values(contextRef.current.fields).some((field) => field.valid === false);
contextRef.current.createFormData = () => {
const data = reduceFieldsToValues(contextRef.current.fields);
return objectToFormData(data, { indices: true });
};
- contextRef.current.setModified = (modified) => {
- contextRef.current.modified = modified;
- };
-
- contextRef.current.setSubmitted = (submitted) => {
- contextRef.current.submitted = submitted;
- };
-
- contextRef.current.setProcessing = (processing) => {
- contextRef.current.processing = processing;
- };
+ contextRef.current.setModified = setModified;
+ contextRef.current.setProcessing = setProcessing;
+ contextRef.current.setSubmitted = setSubmitted;
useThrottledEffect(() => {
refreshCookie();
}, 15000, [fields]);
useEffect(() => {
- contextRef.current.modified = false;
- }, [locale, contextRef.current.modified]);
+ setModified(false);
+ }, [locale]);
const classes = [
className,
@@ -301,13 +283,20 @@ const Form = (props) => {
...contextRef.current,
}}
>
-
- {children}
+
+
+
+
+ {children}
+
+
+
+
);
};
@@ -318,7 +307,7 @@ Form.defaultProps = {
ajax: true,
method: 'POST',
action: '',
- handleAjaxResponse: null,
+ handleResponse: null,
onSuccess: null,
className: '',
disableSuccessStatus: false,
@@ -331,7 +320,7 @@ Form.propTypes = {
ajax: PropTypes.bool,
method: PropTypes.oneOf(['post', 'POST', 'get', 'GET', 'put', 'PUT', 'delete', 'DELETE']),
action: PropTypes.string,
- handleAjaxResponse: PropTypes.func,
+ handleResponse: PropTypes.func,
onSuccess: PropTypes.func,
children: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
diff --git a/src/client/components/forms/Form/initContextState.js b/src/client/components/forms/Form/initContextState.js
index 9ae8d322d9..ff449921b6 100644
--- a/src/client/components/forms/Form/initContextState.js
+++ b/src/client/components/forms/Form/initContextState.js
@@ -1,7 +1,4 @@
export default {
- processing: false,
- modified: false,
- submitted: false,
getFields: () => { },
getField: () => { },
getData: () => { },
diff --git a/src/client/components/forms/Form/useForm.js b/src/client/components/forms/Form/useForm.js
deleted file mode 100644
index 6d968ee4ec..0000000000
--- a/src/client/components/forms/Form/useForm.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { useContext } from 'react';
-import FormContext from './FormContext';
-
-export default () => useContext(FormContext);
diff --git a/src/client/components/forms/Form/useFormFields.js b/src/client/components/forms/Form/useFormFields.js
deleted file mode 100644
index 749ef7627f..0000000000
--- a/src/client/components/forms/Form/useFormFields.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { useContext } from 'react';
-import FieldContext from './FieldContext';
-
-export default () => useContext(FieldContext);
diff --git a/src/client/components/forms/Submit/index.js b/src/client/components/forms/Submit/index.js
index 85b11ce3bb..7dc4833be1 100644
--- a/src/client/components/forms/Submit/index.js
+++ b/src/client/components/forms/Submit/index.js
@@ -1,6 +1,6 @@
-import React, { useContext } from 'react';
+import React from 'react';
import PropTypes from 'prop-types';
-import FormContext from '../Form/FormContext';
+import { useFormProcessing } from '../Form/context';
import Button from '../../elements/Button';
import './index.scss';
@@ -8,12 +8,13 @@ import './index.scss';
const baseClass = 'form-submit';
const FormSubmit = ({ children }) => {
- const formContext = useContext(FormContext);
+ const processing = useFormProcessing();
+
return (
diff --git a/src/client/components/forms/field-types/Auth/APIKey.js b/src/client/components/forms/field-types/Auth/APIKey.js
index 3b2461784c..706740a9b7 100644
--- a/src/client/components/forms/field-types/Auth/APIKey.js
+++ b/src/client/components/forms/field-types/Auth/APIKey.js
@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import React, { useMemo, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import { v4 as uuidv4 } from 'uuid';
import useFieldType from '../../useFieldType';
@@ -6,19 +6,21 @@ import Label from '../../Label';
import Button from '../../../elements/Button';
import CopyToClipboard from '../../../elements/CopyToClipboard';
import { text } from '../../../../../fields/validations';
-import useFormFields from '../../Form/useFormFields';
+import { useFormFields } from '../../Form/context';
import './index.scss';
const path = 'apiKey';
const baseClass = 'api-key';
-const validate = val => text(val, { minLength: 24, maxLength: 48 });
+const validate = (val) => text(val, { minLength: 24, maxLength: 48 });
const APIKey = (props) => {
const {
initialData,
} = props;
+ const [initialAPIKey, setInitialAPIKey] = useState(null);
+
const { getField } = useFormFields();
const apiKey = getField(path);
@@ -36,7 +38,7 @@ const APIKey = (props) => {
const fieldType = useFieldType({
path: 'apiKey',
- initialData: initialData || uuidv4(),
+ initialData: initialData || initialAPIKey,
validate,
});
@@ -45,6 +47,10 @@ const APIKey = (props) => {
setValue,
} = fieldType;
+ useEffect(() => {
+ setInitialAPIKey(uuidv4());
+ }, []);
+
const classes = [
'field-type',
'api-key',
@@ -52,7 +58,7 @@ const APIKey = (props) => {
].filter(Boolean).join(' ');
return (
- <>
+