react-bootstrap modal 消失而不将 showModal 设置为 false

问题描述 投票:0回答:1

我有一个来自react-bootstrap的登录模态,当我填写用户名和密码并单击登录时,它会消失,而无需等待

showLoginModal
设置为false。这是组件:

import { Modal } from 'react-bootstrap'
const AccountsMenu: React.FC = () => {
    const dispatch = useDispatch()
    const navigate = useNavigate()
    const accounts = useSelector((state: RootState) => state.accounts)
    const location = useLocation()
    const getCurrentPath = () => location.pathname + encodeURIComponent(location.search)
    useEffect(() => {
        dispatch(getUserInfoAction())
    }, [dispatch])
    
    const registerPage = () => {
        navigate(ROUTES.REGISTER_ROUTE)
    }
    const [showLoginModal, setShowLoginModal] = useState(false)
    const [username, setUsername] = useState<string>('')
    const [password, setPassword] = useState<string>('')
    const [usernameError, setUsernameError] = useState<string>('')
    const [passwordError, setPasswordError] = useState<string>('')
    const login = () => {
        // Check if username and password are not empty
        if (!username.trim()) {
            setUsernameError('Username cannot be empty.')
            return
        } else {
            setUsernameError('')
        }

        if (!password.trim()) {
            setPasswordError('Password cannot be empty.')
            return
        } else {
            setPasswordError('')
        }
        dispatch(actions.loginUser({ username: username, password: password }))
        setUsername('')
        setPassword('')
    }
    useEffect(() => {
        if (accounts.apiSuccess) {
            setShowLoginModal(false)
        }
    }, [accounts.apiSuccess])
    if (accounts.loading) return <li>Loading ...</li>
    return (
        <li className="nav-item dropdown">
            <a className="nav-link dropdown-toggle" href="#" id="navbarDropdownMenuLink" role="button" data-bs-toggle="dropdown" aria-expanded="false">
                Account
            </a>
            <ul className="dropdown-menu">
                {accounts.userInfo.is_active ? (
                    <li>
                        <a href={'/b/logout?next=' + getCurrentPath()} className="dropdown-item">
                            Logout
                        </a>
                    </li>
                ) : (
                    <>
                        <li>
                            <a href={'/b/login?next=' + getCurrentPath()} className="dropdown-item">
                                Login
                            </a>
                        </li>
                        <li>
                            <button onClick={() => registerPage()} className="dropdown-item">
                                Register
                            </button>
                        </li>
                        <li>
                            <button onClick={() => setShowLoginModal(true)} className="dropdown-item">
                                Login modal
                            </button>
                        </li>
                    </>
                )}
            </ul>
            <Modal show={showLoginModal} onHide={() => setShowLoginModal(false)} centered={true}>
                <div className="d-flex justify-content-center m-3">
                    <ErrorHandling error={accounts.error} loading={accounts.loading} />
                </div>
                <form className="p-4">
                    <div className="form-outline mb-4">
                        <label className="form-label" htmlFor="username">
                            User name:
                        </label>
                        <input
                            type="text"
                            id="username"
                            className={`form-control ${usernameError ? 'is-invalid' : ''}`}
                            value={username}
                            onChange={(e) => {
                                setUsername(e.target.value)
                                setUsernameError('')
                            }}
                        />
                        {usernameError && <div className="invalid-feedback">{usernameError}</div>}
                    </div>
                    <div className="form-outline mb-4">
                        <label className="form-label" htmlFor="password">
                            password:
                        </label>
                        <input
                            type="password"
                            id="password"
                            className={`form-control ${passwordError ? 'is-invalid' : ''}`}
                            value={password}
                            onChange={(e) => {
                                setPassword(e.target.value)
                                setPasswordError('')
                            }}
                        />
                        {passwordError && <div className="invalid-feedback">{passwordError}</div>}
                    </div>
                    <div className="form-outline mt-5 text-center">
                        <button type="button" className="btn btn-primary" onClick={() => login()}>
                            Login
                        </button>
                    </div>
                </form>
            </Modal>
        </li>
    )
}

到目前为止我已经尝试过以下方法:

  1. 我已将登录按钮类型更改为“按钮”而不是“提交”,以防止表单刷新页面。
  2. 我尝试使用
    div
    标签而不是
    form
    标签,但其行为仍然相同。
  3. 我尝试将登录名
    button
    移到
    form
    之外,但行为仍然相同。

我搜索了类似的问题,但没有一个解决这个问题。

问题更新:

我尝试注释掉登录的不同部分,导致此问题的部分是

dispatch(actions.loginUser({ username: username, password: password }))
部分。我不知道如何防止这种情况。或者如果我不能,我怎样才能以其他方式解决这个问题。

javascript reactjs redux react-bootstrap
1个回答
0
投票

我找到的解决方案:

所以,正如我之前猜测的,问题出在这一部分:

dispatch(actions.loginUser({ username: username, password: password }))
。换句话说,当 redux 存储发生更改时,它会导致页面重新渲染。但如果我们想更准确地说,这是导致页面重新渲染的部分:

 if (accounts.loading) return <li>Loading ...</li>

所以之前,我们的账户类型的 redux store 是这样的:

export interface AccountsStoreType {
    error: string | { [key: string]: string } | null
    loading: boolean
    userInfo: UserInfoType
    registerSuccess: boolean | null
}

export interface UserInfoType {
    username?: string
    first_name?: string
    last_name?: string
    email?: string
    is_active: boolean
    is_staff: boolean | null
}

我们有一个

loading
和一个
error
键用于与用户相关的所有操作,例如登录、注销、注册和获取用户信息。

所以,我尝试将商店分开:


export interface LoginType {
    loading: boolean
    success: boolean | null
    error: string | { [key: string]: string } | null
}
export interface RegisterType {
    loading: boolean
    success: boolean | null
    error: string | { [key: string]: string } | null
}
export interface LogoutType {
    loading: boolean
    success: boolean | null
    error: string | { [key: string]: string } | null
}
export interface UserInfoType {
    error: string | { [key: string]: string } | null
    loading: boolean
    username?: string
    first_name?: string
    last_name?: string
    email?: string
    is_active: boolean
    is_staff: boolean | null
    about_me?: string
    user_score?: number
    user_contributions?: UserContributionType[]
}
export interface AccountsStoreType {
    login: LoginType
    register: RegisterType
    logout: LogoutType
    userInfo: UserInfoType
}

分离类型后,我在本答案开头指出的特定行被转换为:

    if (accounts.userInfo.loading) return <li>Loading ...</li>

如您所见,现在它从自己的相关存储中获取

loading
,并且注册对渲染这部分没有任何影响。

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