【问题标题】:Two independent state piece causing infinite loop - useEffect两个独立的状态块导致无限循环 - useEffect
【发布时间】:2022-08-02 18:40:37
【问题描述】:

我无法解决我遇到的问题基本上我提交表单并检查是否有空值。然后我将输入边框涂成红色或绿色。但是,我需要一直重新绘制边框,这意味着如果用户输入一个值,边框应该变成绿色(因此是 useEffect)。我这里有 2 个状态。一个跟踪验证错误索引(对于 value === \'\'),另一部分是 createForm 状态(表单字段)本身。 然后我通过道具发送索引。

注意:无限循环不是在初始渲染时发生,而是在表单以空值提交时发生。如果表单提交上没有空字段,则不会发生无限循环。

我愿意根据需要分享更多信息。

      const [createForm, setCreateForm] = React.useState(() => createFormFields);
      const [validationErrorIndexes, setValidationErrorIndexes] = React.useState([]);

//Function that is being triggered in useEffect - to recalculate validaiton error indexes and resets the indexes.
  const validateFormFields = () => {

    const newIndexes = [];

    createForm.forEach((field, i) => {
      if (!field.value) {
        newIndexes.push(i);
      }
    })

    setValidationErrorIndexes(newIndexes);
  }

//(infinite loop occurs here).
  React.useEffect(() => {

    if (validationErrorIndexes.length) {
      validateFormFields();
      return;
    }

  }, [Object.values(createForm)]);


//Function form submit.
  const handleCreateSubmit = (e) => {
    e.preventDefault();

    if (createForm.every(formField => Boolean(formField.value))) {
      console.log(createForm)
      // TODO: dispatch -> POST/createUser...
    } else {
      validateFormFields();
    }
  }



//I then pass down validationErrorIndexes via props and add error and success classes conditionally to paint the border.
 {createForm && createForm.length && createForm.map((formEl, i) => {

                if (formEl.type === \'select\') {
                  return (
                    <Select
                      className={`create-select ${(validationErrorIndexes.length && validationErrorIndexes.includes(i)) && \'error\'}`}
                      styles={customStyles}
                      placeholder={formEl.label}
                      key={i}
                      value={formEl.value}
                      onChange={(selectedOption) => handleOptionChange(selectedOption, i)}
                      options={formEl.options}
                    />
                  )
                }


                return (
                  <CustomInput key={i} {...{ label: formEl.label, type: formEl.type, value: formEl.value, formState: createForm, formStateSetter: setCreateForm, i, validationErrorIndexes }} />
                )
              })}




    标签: reactjs use-effect


    【解决方案1】:

    好的,这就是正在发生的事情:

    1. 初始渲染 -validationError 索引为空,错误的 useEffect 未命中 if 并通过。

    2. 您单击带有 1 个空字段的提交 - 提交调用 validateFormFields,它计算,设置了 setValidationErrorIndexes,现在它的长度不为零,并且错误的 useEffect 中的 if 将被命中。在这里我们遇到了一个问题......

      问题:在您的依赖数组中的组件Object.values(createForm) 的每次重新呈现时,都会评估并返回新的[数组]。每一次重新渲染,不是旧的具有相同数据,新的具有相同的数据。并且假设 if 由于长度不为 0 而现在已经消失了 - 再次调用 validateFormFields。它进行评估,并使用setValidationErrorIndexes 设置新数据。这会导致重新渲染。 Object.values(createForm) 再次返回一个新数组。好可怜。

      所以基本上,2个解决方案。

      一个很明显,只需将[Object.values(createForm)] 替换为[createForm]。 (为什么你在这里需要 Object.values 顺便说一句?)

      第二个 - 好吧,如果必须拥有[Object.values(createForm)]

        const validateFormFields = () => {
          const newIndexes = [];
          console.log(createForm);
          createForm.forEach((field, i) => {
            if (!field.value) {
              newIndexes.push(i);
            }
          });
          console.log(newIndexes);
          setValidationErrorIndexes((oldIndexes) => {
            // sorry, just an idea. Compare old and new one and return old if equals.
            if (JSON.stringify(oldIndexes) === JSON.stringify(newIndexes)) {
              return oldIndexes; // will not cause rerender.
            }
      
            return newIndexes;
          });
        };
      

    【讨论】:

    • 谢谢@Sergey Sosunov,这澄清了!我认为我必须更具体才能让 useEffect 观察“值”字段的变化。因此在那里使用 Object.values ......
    猜你喜欢
    • 2020-08-27
    • 2020-11-16
    • 2021-11-01
    • 2021-09-27
    • 2020-11-14
    相关资源
    最近更新 更多