【问题标题】:setState not updating state on initial submit, only on subsequent submitssetState 在初始提交时不更新状态,仅在后续提交时更新
【发布时间】:2019-10-02 06:39:04
【问题描述】:

我正在尝试使用会话存储来设置一些数据,它第一次不起作用,但第二次起作用。

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": userData.token, 
          "userId": userData.userId, 
          "expiresIn": userData.expiresIn 
        }));
    } catch(err) {
      setLoginErr(err);
    };
  };


我希望它在初始提交时设置状态,但是当我再次单击提交时设置它没关系

【问题讨论】:

  • 嗨 ryan,刚刚给您写了一个解决方案,如果您有任何问题,请告诉我。

标签: reactjs async-await react-hooks


【解决方案1】:

setUserData() 方法是异步的,这意味着在它自己的逻辑完成之前,没有什么可以阻止在它之后编写的代码执行。这适用于所有状态更新方法。

可能发生的情况是 sessionStorage.setItem() 块在您完全更新前一个块中的状态之前运行。所以第一次没有什么可以保存在 localStorage 中。但在随后的尝试中,状态会使用上一次更新中的令牌/用户信息进行更新。

有几种方法可以解决这个问题:

1) 只是用您创建的变量更新本地存储,而不是等待状态完成:

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": token, 
          "userId": userId, 
          "expiresIn": expiresIn 
        }));
    } catch(err) {
      setLoginErr(err);
    };
  };

2) 使用useEffect() 在状态变化时更新localStorage。

  useEffect(() => {
        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
          "token": userData.token, 
          "userId": userData.userId, 
          "expiresIn": userData.expiresIn 
        }));
  }, [user]) //swap user with whatever you called your state

  const login = async (email, password) => {
    try {
        const user = await loginUser({
          variables: {
            email,
            password
          }
        });

        const { userId, token, expiresIn } = user.data.loginUser;

        setUserData({
          token: token,
          userId: userId,
          expiresIn: expiresIn
        })

    } catch(err) {
      setLoginErr(err);
    };
  };

【讨论】:

    【解决方案2】:

    React Hook 中的useState 也是asynchronous,就像React Component 中的this.setState

    所以,你可以试试:

    const login = async (email, password) => {
        try {
            const user = await loginUser({
              variables: {
                email,
                password
              }
            });
    
            const { userId, token, expiresIn } = user.data.loginUser;
    
            // setUserData({
            //   token: token,
            //   userId: userId,
            //   expiresIn: expiresIn
            // })
            // userData here not yet updated
            sessionStorage.setItem('interdevs-data', JSON.stringify({ 
              "token": token, 
              "userId": userId, 
              "expiresIn": expiresIn 
            }));
            // In your case, you can direct access to user.data.loginUser. Don't need use setUserData
        } catch(err) {
          setLoginErr(err);
        };
      };
    

    或者,如果您仍想使用setUserData,请尝试应用useEffect,例如:

    const login = async (email, password) => {
        try {
            const user = await loginUser({
              variables: {
                email,
                password
              }
            });
            const { userId, token, expiresIn } = user.data.loginUser;
            setUserData({
               token: token,
               userId: userId,
               expiresIn: expiresIn
            })
        } catch(err) {
          setLoginErr(err);
        };
      };
    
    useEffect(() => {
        sessionStorage.setItem('interdevs-data', JSON.stringify({ 
              "token": userData.token, 
              "userId": userData.userId, 
              "expiresIn": userData.expiresIn 
            }));
    }, [userData])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-08
      • 2019-01-23
      • 2019-11-11
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      相关资源
      最近更新 更多