Search code examples
javascriptreactjsmaterial-uireact-material-ui-form-validator

How to handle errors in my form fields with a single function in ReactJS?


I have a form where the user needs to answer 3 questions to be able to register a new password. All fields are mandatory, and the user is unable to send the data to the server until the 3 questions are answered.

My question is how to handle input field errors with only one function? I currently perform a function for each of the fields. And this is not very good at performance levels.

For example, with just one function I can get the values entered in all input fields:

const handleChangeField = (field) => (event) => {
  const value = event?.target?.value || "";
  setData((prev) => ({ ...prev, [field]: value }));
};

Can you tell me if it is possible to create a function similar to the one above, but to handle errors? In this moment that's what I'm doing:

<TextField
  label="What is your mother's name?"
  className={classes.input}
  error={hasErrorMother}
  helperText={hasErrorMother ? "Required field*" : ""}
  value={data.motherName}
  onInput={(event) =>
    event.target.value.length > 0
      ? setHasErrorMother(false)
      : setHasErrorMother(true)
  }
  onChange={handleChangeField("motherName")}
/>

I handle errors for each of the fields within onInput.

Here's the code I put into codesandbox

Thank you very much in advance.


Solution

  • Here is an idea: you keep using handleChangeField but with a few modifications to also handle the error as well. But first, we need to change the state title bit:

    // Remove those
    // const [hasErrorMother, setHasErrorMother] = useState(false);
    // const [hasErrorBorn, setHhasErrorBorn] = useState(false);
    // const [hasErrorPet, setHasErrorPet] = useState(false);
    
    // Instead have the error state this way
    const [error, setError] = useState({
      motherName: false,
      birthplace: false,
      petName: false
    });
    
    ...
    // handleChangeField will have an extra line for error handling
    const handleChangeField = (field) => (event) => {
      const value = event?.target?.value || "";
      setData((prev) => ({ ...prev, [field]: value }));
      setError((prev) => ({ ...prev, [field]: value.length === 0 })); // THIS ONE
    };
    

    And in the return statement, the TextField will change to be:

    // onInput is removed, because onChange is taking care of the error
    <TextField
      label="What is your mother's name?"
      className={classes.input}
      error={error.motherName}
      helperText={error.motherName? "Required field*" : ""}
      value={data.motherName}
      onChange={handleChangeField("motherName")}
    />
    

    Now for the handleContinueAction, this will also change as follows:

    ...
    const handleContinueAction = () => {
      const isValid =
        data.motherName.length > 0 &&
        data.birthplace.length > 0 &&
        data.petName.length > 0;
    
      if (isValid) {
        console.log("Ok, All data is valid, I can send this to the server now");
      } else {
        // If you want to show error for the incomplete fields
        setError({
          motherName: data.motherName.length === 0,
          birthplace: data.birthplace.length === 0,
          petName: data.petName.length === 0
        })
      }
    };
    
    ...
    // and git rid of this part
    // const validateFields = (body) => {
    //   if (body.motherName.length === 0) {
    //     return setHasErrorMother(true);
    //   }
    
    //   if (body.birthplace.length === 0) {
    //     return setHhasErrorBorn(true);
    //   }
    
    //   if (body.petName.length === 0) {
    //     return setHasErrorPet(true);
    //   }
    
    //   return true;
    };