我知道setState的异步性质,但是我仍然不太了解我的问题

时间:2019-07-29 15:58:12

标签: reactjs

我有一个简单的表格,带有几个文本输入。一个是必需的,一个不是必需的。我有一个自定义输入,每次用户按下Enter键时,它就会添加到列表中,并且是必需的。当用户提交表单时,我检查所有必填字段均具有值。

如果我为所有必填字段输入了一个值,然后按Enter,我将收到一条消息,指出该表格无效。如果我再按一次Enter键两次,我将最终收到一条消息,提示我表单有效。

当我在表单提交时console.log记录PriorityArrayValid,demoFieldTwoValid和formValid的值时,它们都是默认值false,直到我按Enter几次为止。

我知道我的问题很普遍。我知道它与setState和async有关,但我看不到问题。

下面是用户点击Enter时运行的代码。

validateField(fieldName, value) {
    let fieldValidationErrors = this.state.formErrors;
    let prioritiesArrayValid = this.state.prioritiesArrayValid;
    let demoFieldTwoValid = this.state.demoFieldTwoValid;
    let prioritiesArray = this.state.prioritiesArray;
    let demoFieldTwo = this.state.demoFieldTwo;

    switch (fieldName) {
      case "prioritiesArray":
        prioritiesArrayValid = value.length > 0;

        fieldValidationErrors.prioritiesArray = prioritiesArrayValid
          ? ""
          : " is required";
        this.setState(
          {
            prioritiesArray: prioritiesArray,
            prioritiesArrayValid: prioritiesArrayValid
          },
          () => {
            return {
              prioritiesArray: value,
              prioritiesArrayValid: prioritiesArrayValid
            };
          }
        );
        break;
      case "demoFieldTwo":
        demoFieldTwoValid = value.length > 0;

        fieldValidationErrors.demoFieldTwo = demoFieldTwoValid
          ? ""
          : " is required";
        console.log("...demoFieldTwo", demoFieldTwo);
        this.setState(
          { demoFieldTwo: demoFieldTwo, demoFieldTwoValid: demoFieldTwoValid },
          () => {
            return {
              demoFieldTwo: value,
              demoFieldTwoValid: prioritiesArrayValid
            };
          }
        );

        break;
      default:
        break;
    }

    this.setState(
      {
        formErrors: fieldValidationErrors
      },
      this.validateForm
    );
  }

  validateForm() {
    let formValid = this.state.formValid;
    this.setState({ formValid: formValid }, () => {
      return {
        formValid:
          this.state.prioritiesArrayValid && this.state.demoFieldTwoValid
      };
    });
    // console.log("this.state.formValid", this.state.formValid);
  }

  handleUserInput(e) {
    const name = e.target.name;
    const value = e.target.value;
    localStorage.setItem(name, value);
    this.setState({ [name]: value });
  }

  validateFields() {
    document
      .getElementById("form")
      .querySelectorAll("[required]")
      .forEach(el => {
        this.validateField(el.name, el.value);
      });
  }

  submitForm(e) {
    e.preventDefault();

    this.validateFields();
    if (this.state.formValid) {
      console.log("FORM VALID");
    } else {
      console.log("this.state.formErrors", this.state.formErrors);
    }
  }

1 个答案:

答案 0 :(得分:1)

如果您有一个沙箱或类似的东西,那就太好了,所以我们可以看到您正在处理的内容的全部范围,而不仅仅是问题代码。

据我所知,您正在过多使用状态,并且希望在设置状态以确定是否应提交表单后收到当前状态。这并不是您想要的理想方式。

您的validateFields()调用是同步的,因此请在不使用状态的情况下验证每个字段,然后在获得所有验证后,然后将状态设置为存在任何错误,然后根据那个。

有点像这样:

  /**
   *  Returns true if all fields validate, false if not.
   *
   *  @invokes this.setState() - state is set with whatever validation errors are found
   */
  validateFields() {
    const errors = [];

    const elems = document.querySelectorAll("#form [required]")
      .forEach(el => {
        const error = this.validateField(el.name, el.value);
        if (error) {
          errors.push(error);
        }
      });

    if (errors.length > 0) {
      this.setState({}); // <-- this should be your only set state? Set whatever you have to here, and let your app display your errors based on this.
      return false;
    } else {
      return true;
    }
  }

  submitForm(e) {
    e.preventDefault();

    if (this.validateFields()) {
      console.log("FORM VALID"); // Proceed to process the form!
    } else {
      console.log("this.state.formErrors", this.state.formErrors);
    }
  }

就像我说的,如果您可以提供沙箱或可以叉的东西,我可能会更好地证明我的意思。

我希望这会有所帮助!