等待反应状态在功能组件中更新

Waiting for react state to update in function component

如何确保handleOpen仅在所有状态(nameErroremailErrormessageError)更新后执行?我的问题是,由于状态不会立即更新,有时 handleOpen 在不应该执行的时候执行。

const handleSend = (e) => {
e.preventDefault();
if (name === "") {
  setNameError(true);
}
if (email === "") {
  setEmailError(true);
  setEmailErrorMessage("Please type your email!");
}
if (!email.includes("@")) {
  setEmailError(true);
  setEmailErrorMessage("Invalid email address");
}
if (message === "") {
  setMessageError(true);
}
if (!nameError && !emailError && !messageError) {
  handleOpen();
}

};

您可以使用 React 的 useRef 钩子,因为它不是反应式的,即不会导致页面重新呈现,所以您确定

if (!nameError && !emailError && !messageError) {
  handleOpen();
}

按照你想要的顺序在正确的时候执行,正如我将在下面显示的那样

const setNameError = useRef(null);
const setEmailError = useRef({value : false, message : ''});
const setMessageError = useRef(null);
const handleSend = (e) => {
e.preventDefault();
if (name === "") {
  setNameError.current = true;
}
if (email === "") {
  setEmailError.current.value = true;
  setEmailError.current.message = "Please type your email!";
}
if (!email.includes("@")) {
  setEmailError.current.value = true;
  setEmailError.current.message = "Invalid email address";
}
if (message === "") {
  setMessageError.current = true;
}
if (!setNameError.current && !setRmailError.current && !setMessageError.current) {
  handleOpen();
}
};

我使用了错误的命名转换来配合你的例子,但在现实生活中你不会像我那样选择 setNameError 作为变量名,但也许你会选择 nameError

我将对您处理错误的方式进行整体重构,但回答您的问题时,您可以这样做:

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

    const isNameEmpty = name === "";
    const isEmailEmpty = email === "";
    const isEmailAtMissing = !email.includes("@");
    const isMessageEmpty = message === "";

    setNameError(isNameEmpty);
    setEmailError(isEmailEmpty || isEmailAtMissing);
    setEmailErrorMessage(isEmailEmpty ? "Please type your email!" : "Invalid email address");
    setMessageError(isMessageEmpty);

    if ([isNameEmpty, emailError, emailError].some(value => !!value)) {
        handleOpen()
    }
}

如果您将“错误”保存在变量中,则确保您正在检查您在状态中使用的最后一个值。

我看到您正在为 JS 事件循环而苦苦挣扎。 React 状态将在事件循环完成后更新。所以你不能指望它们在你的处理函数中立即更新。

然而,还有一些其他解决方案,例如使用 setTimeout(..., 0) 来欺骗事件循环,在这种情况下这对您没有帮助。

这里您需要重构处理程序方法来处理函数范围内的错误状态,并将最终结果设置为错误状态。

const handleSend = (e) => {
  e.preventDefault();
  
  const errors = {
    name: '',
    email: '',
    message: '',
  };
  
  if (name === "") {
    errors.name = "Please enter your name";
  }

  if (email === "") {
    errors.email = "Please type your email!";
  }

  if (!email.includes("@")) {
    errors.email = "Invalid email address";
  }

  if (message === "") {
    errors.email = "Please enter a message";
  }

  setNameError(!!errors.name);
  setNameErrorMessage(errors.name);
  setEmailError(!!errors.email);
  setEmailErrorMessage(errors.email);
  setMessageError(!!errors.message);
  setMessageErrorMessage(errors.message);

  if (Object.values(errors).filter(Boolean).length === 0) {
     handleOpen();
  }
}

我强烈建议重构您的应用程序中的错误处理过程。你的解决方案和我在这里写的解决方案根本没有效率。

祝你好运;)

对于此类问题,您可以遵循的最佳方案是创建另一个状态或什至是一个具有验证检查的常量,然后将其放入 useEffect 中以检查值是否已更改,然后每当它已更改,您检查它是否成立。为了更好地理解你可以这样做:

const [wholeValidate, setWholeValidate] = useState(false);

const handleSend = (e) => {
e.preventDefault();
if (name === "") {
  setNameError(true);
}
if (email === "") {
  setEmailError(true);
  setEmailErrorMessage("Please type your email!");
}
if (!email.includes("@")) {
  setEmailError(true);
  setEmailErrorMessage("Invalid email address");
}
if (message === "") {
  setMessageError(true);
}

if (!nameError && !emailError && !messageError) {
  setWholeValidate(true);  
}

useEffect(() => {
  if(wholeValidate) {handleOpen();}
}, [wholeValidate])