React 异步不会触发重新渲染

问题描述 投票:0回答:1
const AUTH_DISABLED = 0;
const AUTH_LOGIN = 1;
const AUTH_LOGOUT = 2;

function App() {
  const [showLoginPopup, setShowLoginPopup] = useState(false);
  const [authButtonState, setAuthButtonState] = useState(AUTH_DISABLED);

  const handleClick = () => {
    if ( authButtonState == AUTH_LOGOUT ) {
      authGlobal.logout().then( () => { setAuthButtonState(AUTH_LOGIN) } );
    } else {
      setShowLoginPopup(true)
    }
  };

    if (authButtonState === AUTH_DISABLED) {
      authGlobal.tryAuthentication().then((loggedIn) => {
        setAuthButtonState(loggedIn ? AUTH_LOGOUT : AUTH_LOGIN);
      });
    } 

  return (
    <div className="main-container">
      <div> Display </div>
      <div className='main-controls'>
        <button type='button' onClick={handleClick} disabled = {authButtonState == AUTH_DISABLED}>Log {authButtonState == AUTH_LOGOUT ? "Out" : "In"} </button>
        <LoginPopup isVisible={showLoginPopup}/>
      </div>
    </div>
  )
}

在上面的代码中

tryAuthentication
是异步的,有3个路径:凭证位于本地存储中,凭证位于URL中(仅使用外部应用程序登录)或没有任何可登录的内容。

我的问题是,在第二种情况下,按钮不会更改为“注销”。状态永远不会更新,但

then()
正确调用
setAuthButtonState()

将该分支放入

useEffect()
有帮助,但我不知道为什么。 不应该
then()
在没有
UseEffect()
的情况下使用新状态对另一个重新渲染进行排队吗?

javascript reactjs asynchronous react-hooks
1个回答
0
投票

我重构了您的组件,以便更好地处理异步身份验证流程。

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

const AUTH_DISABLED = 0;
const AUTH_LOGIN = 1;
const AUTH_LOGOUT = 2;

function App() {
  const [showLoginPopup, setShowLoginPopup] = useState(false);
  const [authButtonState, setAuthButtonState] = useState(AUTH_DISABLED);

  useEffect(() => {
    // This effect runs only once after the component mounts
    authGlobal.tryAuthentication().then((loggedIn) => {
      setAuthButtonState(loggedIn ? AUTH_LOGOUT : AUTH_LOGIN);
    });
  }, []); // Empty dependency array means it runs once after mount

  const handleClick = () => {
    if (authButtonState === AUTH_LOGOUT) {
      authGlobal.logout().then(() => {
        setAuthButtonState(AUTH_LOGIN);
        setShowLoginPopup(false); // Hide popup on logout
      });
    } else {
      setShowLoginPopup(true);
    }
  };

  return (
    <div className="main-container">
      <div>Display</div>
      <div className="main-controls">
        <button 
          type="button" 
          onClick={handleClick} 
          disabled={authButtonState === AUTH_DISABLED}
        >
          Log {authButtonState === AUTH_LOGOUT ? "Out" : "In"}
        </button>
        {showLoginPopup && <LoginPopup />}
      </div>
    </div>
  );
}

因此,总而言之,虽然 then() 似乎应该在没有 useEffect 的情况下使用新状态对另一个重新渲染进行排队,但实际上,tryAuthentication 函数的异步性质以及 React 批量状态更新的方式可能会导致您观察到的问题。使用 useEffect 提供了一种更加可控和可预测的方式来处理功能组件中的副作用和异步操作。

© www.soinside.com 2019 - 2024. All rights reserved.