diff --git a/package.json b/package.json index 8a870b2..27446ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-validify", - "version": "6.0.3", + "version": "6.0.4", "description": "Form validation made easy", "main": "dist/index.js", "module": "lib/index.js", diff --git a/src/use-field.ts b/src/use-field.ts index a53113d..f76f4f0 100644 --- a/src/use-field.ts +++ b/src/use-field.ts @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useEffect } from "react"; import get from "lodash/get"; import set from "lodash/set"; import validate from "./validate"; @@ -21,7 +21,13 @@ const useField = ({ name, rules: fieldRules }: UseFieldProps) => { rules, } = React.useContext(FormContext); - rules.current[name] = fieldRules || []; + //set the rules when they change, clear when unmounted + useEffect(() => { + rules.current[name] = fieldRules || []; + return () => { + rules.current[name] = []; + }; + }, [fieldRules]); let value = get(values, name); // Pulling out just this field's errors diff --git a/src/use-submit.ts b/src/use-submit.ts index b18d3fe..1bc426b 100644 --- a/src/use-submit.ts +++ b/src/use-submit.ts @@ -31,6 +31,7 @@ const useSubmit = () => { return { values, + errors, handleSubmit, canSubmit: !errors.length, }; diff --git a/tests/form.test.js b/tests/form.test.js index ea312a9..73b366c 100644 --- a/tests/form.test.js +++ b/tests/form.test.js @@ -1,6 +1,6 @@ import React from "react"; -import { render, fireEvent, wait } from "@testing-library/react"; -import { TestForm } from "./helpers/form"; +import { render, fireEvent, wait, act } from "@testing-library/react"; +import { TestForm, TestFormWithRemovedField } from "./helpers/form"; test("Checks dependent rule", async () => { let errorMessage = "Must be longer value than date 2 field"; @@ -122,7 +122,7 @@ test("Submit calls onSubmit if validation passes", async () => { }); test("Form works without rules object passed", async () => { - let { queryByPlaceholderText, queryByText } = render(); + let { queryByPlaceholderText } = render(); //blur the field const name = queryByPlaceholderText("name"); @@ -135,9 +135,7 @@ test("Form works without rules object passed", async () => { test("Empty input value gets passed as empty string to rule fn", async () => { const spy = jest.fn(); - let { queryByPlaceholderText, queryByText } = render( - - ); + let { queryByText } = render(); const submit = queryByText("Submit Form"); //press the submit button @@ -149,8 +147,7 @@ test("Empty input value gets passed as empty string to rule fn", async () => { }); test("Field validation shows errors on submit even without touching any fields", async () => { - let { queryByPlaceholderText, getByText } = render(); - const name = queryByPlaceholderText("name"); + let { getByText } = render(); //trigger submit getByText("Submit Form").click(); @@ -186,3 +183,30 @@ test(`Untouched fields shouldn't validate unless submitted first`, () => { expect(queryByText("This field is required")).toBeNull(); }); + +test(`Doesnt check rule after component is unmounted`, async () => { + const spy = jest.fn(); + let { getByText, queryByPlaceholderText } = render( + + ); + fireEvent.change(queryByPlaceholderText("email"), { + target: { value: "" }, + }); + await act(async () => await new Promise((resolve) => setTimeout(resolve, 0))); + expect(queryByPlaceholderText("email")).toEqual(null); + + fireEvent.change(queryByPlaceholderText("name"), { + target: { value: "testing" }, + }); + fireEvent.change(queryByPlaceholderText("date1"), { + target: { value: "testing" }, + }); + fireEvent.change(queryByPlaceholderText("date2"), { + target: { value: "test" }, + }); + + getByText("Submit Form").click(); + + //it should call submit even though email is empty, because it was unmounted + expect(spy.mock.calls[0][0].email).toEqual(""); +}); diff --git a/tests/helpers/form.tsx b/tests/helpers/form.tsx index 0ecd659..5b00754 100644 --- a/tests/helpers/form.tsx +++ b/tests/helpers/form.tsx @@ -16,6 +16,7 @@ type Props = { noRules?: boolean; nameRule?: RuleFn; onSubmit?: (values: any) => any; + unmountEmail?: boolean; }; type TestValues = { @@ -24,12 +25,19 @@ type TestValues = { name?: string; }; -export const TestForm = ({ onSubmit, noRules, nameRule }: Props) => { +export const TestForm = ({ + onSubmit, + noRules, + nameRule, + unmountEmail, +}: Props) => { let [values, setValues] = useState({ email: "test" }); return (
- + {unmountEmail ? null : ( + + )} @@ -37,3 +45,13 @@ export const TestForm = ({ onSubmit, noRules, nameRule }: Props) => {
); }; + +export const TestFormWithRemovedField = (props: Props) => { + let [unmountEmail, setUnmount] = useState(false); + + useEffect(() => { + setTimeout(() => setUnmount(true), 0); + }, []); + + return ; +};