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().

把 twig 放进useEffect()里有帮助,但我不知道为什么. 难道then()不应该排队另一个重新呈现与新的状态没有UseEffect()

推荐答案

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

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的新状态排队另一个重新呈现,但实际上,您的try Authentication函数的异步性质和Reaction批处理状态更新的方式可能会导致您观察到的问题.使用useEffect提供了一种更可控、更可预测的方式来处理功能组件中的副作用和异步操作.

Javascript相关问答推荐

使用TMS Web Core中的HTML模板中的参数调用过程

我试图实现用户验证的reduxstore 和操作中出了什么问题?

Redux查询多个数据库Api reducerPath&

如何使覆盖div与可水平滚动的父div相关?

google docs boldText直到按行执行应用脚本错误

html + java script!需要帮助来了解为什么我得到(无效的用户名或密码)

JS,当你点击卡片下方的绿色空间,而它是在它的背后转动时,

如何避免页面第一次加载时由于CSS样式通过JavaScript更改而出现闪烁

以Angular 实现ng-Circle-Progress时出错:模块没有导出的成员

当输入字段无效时,我的应用程序不会返回错误

如何在Angular拖放组件中同步数组?

变量在导入到Vite中的另一个js文件时成为常量.

如果一个字符串前面有点、空格或无字符串,后面有空格、连字符或无字符串,则匹配正则表达式

将多个文本框中的输出合并到一个文本框中

我怎样才能得到一个数组的名字在另一个数组?

为什么NULL不能在构造函数的.Prototype中工作

Plotly.js栏为x轴栏添加辅助文本

如何使pdf.js上的文本呈现为可选?

使用Java脚本替换字符串中的小文本格式hashtag

使用JavaScript或PHP从div ID值创建锚标记和链接