【问题标题】:React : always the previous state id taken into account, even with prevState and useEffectReact :总是考虑之前的状态 id,即使使用 prevState 和 useEffect
【发布时间】:2021-10-03 07:07:28
【问题描述】:

我有一个检查密码长度的 checkPassword 函数,该函数在输入密码时触发“onChange”。

这里是函数:

 const checkPassword = () => {
    if (user_password.length >= 10)
      setPasswordFlag({ ...passwordFlag, length: true });
    else setPasswordFlag({ ...passwordFlag, length: false });
   };

这是我输入的密码:

<input type="password" className="input_container" placeholder="Mot de passe" id="password" name="password" onChange={(e) => {
   setUserSignup({
     ...userSignup,
     user_password: e.target.value,
   });
   checkPassword();
 }}
value={userSignup.user_password} ref={refSignupPassword} />

问题是每次都会考虑之前的状态。基本上我的状态 passwordFlag.length 在第 11 个字符而不是第 10 个字符处变为 true。

我尝试使用 prevState,但它并没有改变任何东西。

然后,我尝试像这样使用 useEffect :

const checkPassword = () => {
      useEffect(() => {
        if (user_password.length >= 10)
          setPasswordFlag({ ...passwordFlag, length: true });
        else setPasswordFlag({ ...passwordFlag, length: false });
      }, []);
    };

但是我现在有这个错误:React Hook “useEffect”在函数“checkPassword”中被调用,它既不是 React 函数组件也不是自定义 React Hook 函数。 React 组件名称必须以大写字母开头。 我试图用大写重命名我的函数,但同样的问题。

但是,如果我将 checkPassword 函数放在 onBlur={checkPassword} 中,那么它可以工作。但我需要在“onChange”而不是“onBlur”中修复它

谁能告诉我我需要做什么来确保考虑到正确的状态?

谢谢!

【问题讨论】:

  • 我认为这里的部分问题是竞争条件。 React 中的状态更新是异步/批处理的,你不能设置状态然后立即检查它并期望一致的行为。

标签: reactjs


【解决方案1】:

您不能在函数块中使用“useEffect”。

你可以像这样改变你的功能:

 const checkPassword = (password) => {
    if (password.length >= 10)
      setPasswordFlag({ ...passwordFlag, length: true });
    else setPasswordFlag({ ...passwordFlag, length: false });
   };

还有你的密码输入:

<input type="password" className="input_container" placeholder="Mot de passe" id="password" name="password" onChange={(e) => {
   setUserSignup({
     ...userSignup,
     user_password: e.target.value,
   });
   checkPassword(e.target.value);
 }}
value={userSignup.user_password} ref={refSignupPassword} />

我们将值传递给 checkPassword 函数。现在您的函数可以立即访问密码长度。

【讨论】:

    【解决方案2】:

    checkPassword 需要你刚刚设置的下一个状态值,但这不会;在下一次渲染之前可用。这是因为设置状态会触发新的渲染,并且在下一次渲染中,新状态将可用。但这不会立即改变任何局部变量的值。

    这里至少有两个选项。


    您可以将密码字符串直接传递给checkPassword,就像传递给setUserSignup一样

    setUserSignup({
      ...userSignup,
      user_password: e.target.value,
    });
    checkPassword(e.target.value);
    

    那么checkPassword 不会从任何陈旧状态读取。


    或者创建一个观察setUserSignup 值并在必要时设置一些状态的效果。

    类似这样的:

    useEffect(() => {
      const longEnough = user_password.length >= 10;
      if (passwordFlag.length !== longEnough) {
        setPasswordFlag({ ...passwordFlag, length: longEnough });
      }
    }, [passwordFlag, setPasswordFlag]);
    

    请注意,它会在设置状态之前检查状态是否需要更新。这可以防止无限循环,其中效果更新状态、运行效果、更改状态等......

    请注意,效果在组件的主函数中,而不是在任何回调中。

    例如:

    function MyComponent() {
      const [myState, setMyState] = useState() // setup you custom state here
      
      // effect that watches your state and then sets state if necessary here
      useEffect(() => {...}, [hook, dependencies, here])
    
      return <>...</>
    }
    

    阅读rules of hooks了解更多信息。

    【讨论】:

    • 嗨@Alex Wayne,我已经按照您的第一个提示进行操作了,感谢您的帮助!
    猜你喜欢
    • 2021-12-17
    • 1970-01-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 2023-03-05
    • 1970-01-01
    相关资源
    最近更新 更多