当前位置: 首页 > 知识库问答 >
问题:

React useState()不同步更新值[重复]

壤驷经国
2023-03-14

若在设置值之后调用React useState(),则不会更新变量的值。

我读过useEffect(),但不知道它对这个特定场景有什么用处。

完整代码(请打开控制台选项卡以查看变量状态)

// hook
const [ error, setError ] = useState<boolean>();
const handleSubmit = (e: any): void => {
    e.preventDefault();
    if (email.length < 4) {
      setError(true);
    }
    if (password.length < 5) {
      setError(true);
    }
    console.log(error); // <== still false even after setting it to true
    if (!error) { 
      console.log("validation passed, creating token");
      setToken();
    } else {
      console.log("errors");
    }
  };

共有2个答案

祁博雅
2023-03-14

与< code>setState一样,< code>useState是异步的,倾向于批量更新,以提高性能。使用< code>useEffect是正确的,它允许您在状态更新后有效地执行回调。

文档中的示例:

import React, { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

尽管我们也建议,如果在请求状态更新时需要更新的值,那么最好在组件中只包含一个变量

有关同步使用状态的详细信息

如果您熟悉Redux的减速机,您可以使用use Reduce er作为另一种选择。来自文档:

useReducer 通常比 useState 更可取,当您具有涉及多个子值的复杂状态逻辑时,或者当下一个状态依赖于前一个状态时。useReducer 还允许您优化触发深度更新的组件的性能,因为您可以向下传递调度而不是回调。

禄俊逸
2023-03-14

假设用户没有有效的凭据。问题就在这里:

if (email.length < 4) {  // <== this gets executed
  setError(true);
}
if (password.length < 5) { // <== this gets executed
  setError(true);
}
console.log(error); // <== still false even after setting it to true
if (!error) { // <== this check runs before setError(true) is complete. error is still false.
  console.log("validation passed, creating token");
  setToken();
} else {
  console.log("errors");
}

您正在使用多个独立运行的if检查,而不是使用单个if检查。您的代码执行所有if检查。在一次检查中,当其中一个条件通过时,调用< code>setError(true),但是< code>setError()是异步的。在调用下一个if-check之前,该操作不会完成,这就是为什么它看起来好像您的值从未被保存过。

你可以用if-else和useEffect的组合来更干净地做到这一点:https://codesandbox.io/s/dazzling-pascal-78gqp

import * as React from "react";

const Login: React.FC = (props: any) => {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");
  const [error, setError] = React.useState(null);

  const handleEmailChange = (e: any): void => {
    const { value } = e.target;
    setEmail(value);
  };

  const handlePasswordChange = (e: any): void => {
    const { value } = e.target;
    setPassword(value);
  };

  const handleSubmit = (e: any): void => {
    e.preventDefault();
    if (email.length < 4 || password.length < 5) {
      setError(true);
    } else {
      setError(false);
    }
  };

  const setToken = () => {
    //token logic goes here
    console.log("setting token");
  };

  React.useEffect(() => {
    if (error === false) {
      setToken();
    }
  }, [error]); // <== will run when error value is changed.

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          placeholder="email@address.com"
          onChange={handleEmailChange}
        />
        <br />
        <input
          type="password"
          placeholder="password"
          onChange={handlePasswordChange}
        />
        <br />
        <input type="submit" value="submit" />
      </form>

      {error ? <h1>error true</h1> : <h1>error false</h1>}
    </div>
  );
};

export default Login;
 类似资料:
  • 问题内容: 如果我将某些内容推送到Redis的列表中,然后从该列表中弹出,是否可以保证我会得到较早推送的项目,还是可以在写入之前进行读取? 问题答案: Redis在单个线程中运行(执行后台保存时进行分叉除外,但这无关紧要),因此以后发送的任何请求都必然会在以后运行。这样,您将看到您推送的值。 (不过,再三考虑一下,如果您不愿意并且有意使它故意失败,可能会引发失败。但这将需要通过单独的连接发送请求,

  • 在运行run函数时,我希望value变量的值为“new”,但即使是500毫秒,它仍然是“old”。为什么会发生这种情况,如何解决这个问题?

  • 我正在使用react在我的网站中切换明暗模式。我还希望主题使用localstorage持久化。问题是,当单击switch切换主题时,相应的localstorage主题值不会更新。我知道状态更新是异步的,但我想解决这个问题。 我的代码: 我尝试使用async await,但结果是一样的。

  • Android Studio要求我将gradle升级到3.5.1版本,但一旦我这样做了,它就不再同步了,尽管我没有报告任何明显的错误... 出现的唯一错误消息是“Gradle项目同步失败。基本功能(如编辑、调试)将无法正常工作。” 和我的一些“idea.log”最后条目

  • 问题内容: 有点奇怪,我正在使用JavaFX 8,并且在Jubula测试期间发现了一些奇怪的行为。 我有一个使用以下代码创建的datepicker控件: 效果很好,控件在窗体上创建并按预期工作。如果我使用日历来选择日期,则值会更新。 现在,对于奇怪的部分,如果我输入日期选择器并在(例如2017/10/11)中手动键入日期,然后通过制表符或单击表单上的下一个文本框来退出控件,则日期选择器locald

  • 我正在尝试制作一个菜单系统,其中某些属性的值将在另一个类中更新。 第一种方法 第二种方法与上面相同,案例6应将防御更新为50并重新启动菜单,但当我在打印25后选择案例5时 具有定义变量的类 我已经尝试了很多谷歌搜索,但没有找到解决方案。这段代码只是试图让值更新工作。

  • 我正在尝试使用DidMount中的localStorage值更新状态,但它没有更新: 在第一个console.log中,我的值为1,在第二个中,它保持为空,不更新状态。