diff --git a/.changeset/tasty-colts-watch.md b/.changeset/tasty-colts-watch.md
new file mode 100644
index 00000000..e8c25526
--- /dev/null
+++ b/.changeset/tasty-colts-watch.md
@@ -0,0 +1,5 @@
+---
+"react-cool-form": patch
+---
+
+feat: use unset for clear error
diff --git a/examples/src/BasicForm/index.tsx b/examples/src/BasicForm/index.tsx
index 656cfc98..06b8214d 100644
--- a/examples/src/BasicForm/index.tsx
+++ b/examples/src/BasicForm/index.tsx
@@ -128,16 +128,16 @@ export default (): JSX.Element => {
console.log(
"LOG ===> formState: ",
getState({
- values: "values",
- touched: "touched",
+ // values: "values",
+ // touched: "touched",
errors: "errors",
- isDirty: "isDirty",
- dirtyFields: "dirtyFields",
- isValidating: "isValidating",
- isValid: "isValid",
- isSubmitting: "isSubmitting",
- isSubmitted: "isSubmitted",
- submitCount: "submitCount",
+ // isDirty: "isDirty",
+ // dirtyFields: "dirtyFields",
+ // isValidating: "isValidating",
+ // isValid: "isValid",
+ // isSubmitting: "isSubmitting",
+ // isSubmitted: "isSubmitted",
+ // submitCount: "submitCount",
})
);
@@ -181,7 +181,8 @@ export default (): JSX.Element => {
};
const handleClearErrorsClick = (): void => {
- setFieldError("text.nest");
+ // setFieldError("text.nest");
+ setFieldError("number");
};
const handleValidateClick = (): void => {
@@ -232,9 +233,9 @@ export default (): JSX.Element => {
{
+ ref={validate(async (value) => {
return value.length <= 5 ? "Field error" : "";
- })} */
+ })}
/>
)}
@@ -243,9 +244,9 @@ export default (): JSX.Element => {
{
+ ref={validate(async (value) => {
return value.length <= 5 ? "Field error" : "";
- })} */
+ })}
/>
)}
@@ -254,9 +255,9 @@ export default (): JSX.Element => {
label="Number:"
type="number"
name="number"
- /* ref={validate((value) => {
+ ref={validate((value) => {
return value <= 5 ? "Field error" : "";
- })} */
+ })}
/>
diff --git a/src/useForm.ts b/src/useForm.ts
index 64c4aae6..1f2cdf77 100644
--- a/src/useForm.ts
+++ b/src/useForm.ts
@@ -46,6 +46,7 @@ import {
isRangeField,
isUndefined,
set,
+ unset,
warn,
} from "./utils";
@@ -215,14 +216,16 @@ export default ({
? error(get(stateRef.current.errors, name))
: error;
- if (isKey(name) && !error) {
+ if (error) {
+ setStateRef(`errors.${name}`, error);
+ } else {
setErrors((prevErrors) => {
+ if (!isKey(name)) return unset(prevErrors, name, true);
+
const nextErrors = { ...prevErrors };
delete nextErrors[name];
return nextErrors;
});
- } else {
- setStateRef(`errors.${name}`, error || undefined);
}
},
[setErrors, setStateRef, stateRef]
diff --git a/src/utils.ts b/src/utils.ts
index 7f94fb78..015a1e98 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -82,23 +82,50 @@ const cloneObject = (object: unknown): any => {
};
export const set: Set = (object, path, value, immutable = false) => {
- if (!isPlainObject(object)) return object;
+ if (!isPlainObject(object)) throw new TypeError("Expected an object.");
- const tempPath = String(path)
+ const segs = String(path)
.split(/[.[\]]+/)
.filter(Boolean);
const newObject = immutable ? cloneObject(object) : object;
- tempPath.slice(0, -1).reduce((obj, key, idx) => {
+ segs.slice(0, -1).reduce((obj, key, idx) => {
if (isObject(obj[key])) return obj[key];
- const next = Number(tempPath[idx + 1]);
+ const next = Number(segs[idx + 1]);
obj[key] = Number.isInteger(next) && next >= 0 ? [] : {};
return obj[key];
- }, newObject)[tempPath[tempPath.length - 1] || ""] = value;
+ }, newObject)[segs[segs.length - 1] || ""] = value;
return newObject;
};
+export const unset = (object: any, path: string, immutable = false): any => {
+ if (!isPlainObject(object)) throw new TypeError("Expected an object.");
+
+ const refObject = immutable ? cloneObject(object) : object;
+ let newObject = refObject;
+
+ // eslint-disable-next-line no-prototype-builtins
+ if (newObject.hasOwnProperty(path)) {
+ delete newObject[path];
+ return refObject;
+ }
+
+ if (!isUndefined(get(newObject, path))) {
+ const segs = path.split(".");
+ let last = segs.pop() as string;
+
+ while (segs.length && segs[segs.length - 1].slice(-1) === "\\")
+ last = `${(segs.pop() as string).slice(0, -1)}.${last}`;
+
+ while (segs.length) newObject = newObject[(path = segs.shift() as string)];
+
+ delete newObject[last];
+ }
+
+ return refObject;
+};
+
export const deepMerge = (...objects: any[]) =>
objects.reduce((prev, obj) => {
Object.keys(obj).forEach((key) => {