-1

I have a react function component which returns a simple form . All I want to do is to clear fields' previous errors on submit and then validate fields again. surprisingly the first call of setState isn't applying changes but the others work fine .

here is the whole code :

import React from "react";
import { TextField, Button } from "@material-ui/core";

export default function EditPresonalInfo() {
  const [fields, setFields] = React.useState({
    username: "",
    usernameHelper: "",
    usernameError: false,
    name: "",
    nameHelper: "",
    nameError: false,
  });

  const submitForm = (e) => {
    e.preventDefault();

    setFields({
      ...fields,
      usernameError: false,
      usernameHelper: "",
      nameError: false,
      nameHelper: "",
    });

    if (fields.username.length < 4) {
      setFields({
        ...fields,
        usernameHelper: "use at least 4 characters",
        usernameError: true,
      });
      return;
    }

    if (fields.name.length < 2) {
      setFields({
        ...fields,
        nameHelper: "use at least 2 characters",
        nameError: true,
      });
      return;
    }
  };

  const handleChange = (fieldName) => (event) => {
    setFields({
      ...fields,
      [fieldName]: event.target.value,
    });
  };

  return (
    <form onSubmit={submitForm}>
      <TextField
        label="username"
        onChange={handleChange("username")}
        error={fields.usernameError}
        value={fields.username}
        helperText={fields.usernameHelper}
      />
      <TextField
        label="name"
        onChange={handleChange("name")}
        error={fields.nameError}
        value={fields.name}
        helperText={fields.nameHelper}
      />
      <Button type="submit">submit</Button>
    </form>
  );
}

can someone help me with what I'm missing and whats wrong?

fmatt
  • 464
  • 1
  • 5
  • 15
  • Does this answer your question? [console log the state after using useState doesn't return the current value](https://stackoverflow.com/questions/54867616/console-log-the-state-after-using-usestate-doesnt-return-the-current-value) – Nico_ Sep 10 '20 at 09:45
  • I'd rather use the usual syntax (import { useState } from 'react'; and then useState()) to start. Where are the other calls that you mention? – David Thery Sep 10 '20 at 09:46
  • 1
    Your `fields` is not updated directly at the beginning of your function `submitForm`, it will be updated at the end of the lifecycle. So when you use `fields` later on the function it's still the 'original' value. – Nico_ Sep 10 '20 at 09:48
  • @DavidThery I mean the calls in if statements which properly set helper texts – fmatt Sep 10 '20 at 09:58
  • @Nico_ you mean it is because of the use of ...fields while fields isn't updated yet ? – fmatt Sep 10 '20 at 10:04
  • @fmatt Yes, try to console.log your `fields` you'll see it's not updated (until the next render). – Nico_ Sep 10 '20 at 10:07
  • @Nico_ thats it ! thanks a lot . so if I got it right, states are updated on render not on setState . – fmatt Sep 10 '20 at 10:12

4 Answers4

3

You do not have to set the state for each validation. For this scenario I think it would be best to create your new state first based off of the validations, after which then you set the state.

const submitForm = (e) => {
  e.preventDefault();

  const newFields = { ...fields };

  if (fields.username.length < 4) {
    newFields["usernameHelper"] = "use at least 4 characters";
    newFields["usernameError"] = true;
  } else {
    newFields["usernameHelper"] = "";
    newFields["usernameError"] = false;
  }

  if (fields.name.length < 2) {
    newFields["nameHelper"] = "use at least 2 characters";
    newFields["nameError"] = true;
  } else {
    newFields["nameHelper"] = "";
    newFields["nameError"] = false;
  }

  setFields(newFields);
};

Edit practical-pine-rkho0

95faf8e76605e973
  • 13,643
  • 3
  • 24
  • 51
1

this one worked for me

 const submitForm = (e) => {
    e.preventDefault();
    let usernameHelper = "";
    let usernameError = false;
    let nameError = false;
    let nameHelper = "";

    if (fields.username.length < 4) {
      usernameHelper = "use at least 4 characters";
      usernameError = true;
    }
    if (fields.name.length < 2) {
      nameHelper = "use at least 2 characters";
      nameError = true;
    }
    setFields({
      ...fields,
      usernameError: usernameError,
      usernameHelper: usernameHelper,
      nameError: nameError,
      nameHelper: nameHelper,
    });
  };
That Guy Kev
  • 386
  • 2
  • 10
0

I understand from this you want to apply some validation to your form and hence you're already using MaterialUI, I suggest that you follow this link https://react-hook-form.com/get-started#Applyvalidation. You will find best practices there and easier implementaions.

That Guy Kev
  • 386
  • 2
  • 10
  • thanks for your help but I'm learning react as a begginer and am really curious to see what's going on in this method – fmatt Sep 10 '20 at 10:01
  • lose "return;" in each if statement, in java script the code isn't executed line buy line, so your on Submit function can executes one of the if statements and end before excecuting the rest of the code(most likely the first setFields) – That Guy Kev Sep 10 '20 at 10:23
  • that's right, I was also mistaken doing so . 'cause having multiple errors, just one did appear – fmatt Sep 10 '20 at 10:34
0

I was mistakenly using setFields to change fields at the moment, It can instead be done explicitly like this

const submitForm = (e) => {
    e.preventDefault();

    fields.nameError= false
    fields.usernameError= false
    fields.nameHelper= ""
    fields.usernameHelper= ""

    if (fields.name.length < 2) {
      fields.nameHelper = "use at least 2 characters";
      fields.nameError = true;
    }

    if (fields.username.length < 4) {
      fields.usernameHelper = "use at least 4 characters";
      fields.usernameError = true;
    }

    setFields({
      ...fields
    })
  };
fmatt
  • 464
  • 1
  • 5
  • 15