javascript - 为什么我必须第二次发送一个动作来更新状态?Redux、React、NodeJS、MySQL
问题描述
所以我正在使用 MySQL、Node、React 和 Redux 创建一个用户身份验证登录系统。
我创建了一个注册端点来将注册用户插入到我的 MySQL 数据库中。
然后我创建了一个登录端点来从我的 MySQL 数据库中选择登录用户。
SignUpAndSignInComponent 只返回我的 SignUp 和 SignIn 组件。
我的注册组件使用 Hooks 设置本地状态,然后通过我的注册端点传递到我的后端。
我的登录组件还使用 Hooks 设置本地状态,然后将其传递给我的后端以从数据库中检索用户。
此时我只显示了登录的用户,但只显示在 SignUpAndSignIn 页面上。
我希望能够在我的标题上显示用户登录,所以我需要提升状态。
我现在所做的是引入 Redux 来管理我的状态并在一个大商店中保持登录用户的状态,以便所有组件都可以访问它。
我的 SignIn 组件使用 useDispatch 将操作分派到商店
我希望能够从登录用户那里获取用户名,并将其传递到我最顶层应用程序级别的标题组件中。
我最顶层的 App 组件使用 useSelector 来检索从商店登录的用户并将其显示在我的标题中。
我设法通过创建我的商店、rootReducer、用户减速器、操作和类型来做到这一点。我什至使用 redux-persist 和本地存储保持状态,以便在应用程序级别可见。
我的问题是,当用户登录(单击登录表单上的提交按钮)时,它只会更新本地状态并在其本地视图上显示状态。
只有当我第二次登录时,我的操作才会发送到商店,以便我可以在顶层查看登录用户。为什么是这样?
我需要使用 Redux-thunk 来处理这个异步请求吗?这是我认为我应该做的,但需要更清楚地了解实际问题是什么。
带调度的登录组件表单
``` import React, { useState, useCallback } from 'react';
import Axios from 'axios';
import { useSelector, useDispatch } from 'react-redux';
import { setCurrentUser } from '../../redux/user/user.reducer';
import { Form, Button } from 'react-bootstrap';
import { UserActionTypes } from '../../redux/user/user.types';
const SignIn = () => {
const dispatch = useDispatch();
const [emailLog, setEmailLog] = useState('');
const [passwordLog, setPasswordLog] = useState('');
const [loginStatus, setLoginStatus] = useState('');
const CallBoth = async () => {
await login();
isUserLoggedIn();
}
const login = async () => {
await Axios.post('http://localhost:3001/login', {
email: emailLog,
password: passwordLog
}).then((response) => {
if (response.data.message) {
setLoginStatus(response.data.message);
} else {
setLoginStatus(response.data[0].username);
}
});
}
const isUserLoggedIn = () => {
dispatch({type: UserActionTypes.SET_CURRENT_USER,
payload: loginStatus
});
}
window.onbeforeunload = function (e) {
console.log(e);
return true;
}
return(
<div className="sign-in">
<Form onSubmit={CallBoth} >
<Form.Group controlId="formBasicEmail">
<Form.Label>Email address</Form.Label>
<Form.Control type="email" placeholder="Enter email"
onChange={
(e) => {setEmailLog(e.target.value);
}}
/>
<Form.Text className="text-muted">
We'll never share your email with anyone else.
</Form.Text>
</Form.Group>
<Form.Group controlId="formBasicPassword">
<Form.Label>Password</Form.Label>
<Form.Control type="password" placeholder="Password"
onChange={
(e) => {setPasswordLog(e.target.value);
}}
/>
</Form.Group>
<Form.Group controlId="formBasicCheckbox">
<Form.Check type="checkbox" label="Check me out" />
</Form.Group>
<Button variant="primary" type="submit"
>
Submit
</Button>
</Form>
<h1>{loginStatus}</h1>
</div>
)
}
export default SignIn; ```
带有 useSelector 的 App.js
```import React, { Component, useEffect } from 'react';
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import HomePage from './pages/homepage/homepage.component';
import SignUpAndSignIn from './pages/signupandsignin/signupandsignin.component';
import Header from './components/header/header.component';
import { useSelector, useDispatch } from 'react-redux';
function App() {
const userLoggedIn = useSelector( (state) => state.user.currentUser);
return (
<>
<Router>
<Header />
<h1>User logged in: {userLoggedIn}</h1>
<Switch>
<Route exact path="/" component={HomePage}>
<HomePage />
</Route>
<Route path="/signupandsignin" component={SignUpAndSignIn}>
<SignUpAndSignIn />
</Route>
</Switch>
</Router>
</>
);
}
export default App;
解决方案
看起来这是由于您在登录功能中进行异步调用的方式。您已经使用了异步等待,但您也在使用 .then() 您的 CallBoth 函数正在等待登录函数完成,但它没有等待 .then 调用完成,因此 isUserLoggedIn 正在调度状态更新之前- 它在第二次登录时被捕获,这就是它在第二次登录尝试后工作的原因。
您可以简单地删除 CallBoth 函数并将 isUserLoggedIn 调用放在 setState 调用之后的 .then 中。然后登录功能将是您的提交处理程序
已编辑
这样做时,您不需要将登录功能设为异步等待。此外,您实际上不需要将响应数据设置为状态 - 您可以将其直接传递给 isUserLoggedIn。由于您将数据存储在 redux 存储中,因此您根本不需要将其存储在组件状态中。只需使用您的选择器从 redux 中获取它
您可以修改您的 isUserLoggedIn 函数以接受响应数据作为参数,如下所示:
const isUserLoggedIn = (loginStatus) => {
dispatch({type: UserActionTypes.SET_CURRENT_USER,
payload: loginStatus
});
}
然后在您的登录功能中:
const login = () => {
Axios.post('http://localhost:3001/login', {
email: emailLog,
password: passwordLog
}).then((response) => {
if (response.data.message) {
isUserLoggedIn(response.data.message);
} else {
isUserLoggedIn(response.data[0].username);
}
});
}
推荐阅读
- android - 更改方向时调整大小的绘图应用程序
- android - 移动设备上基于证书的身份验证
- python - 使用字符串搜索字典列表并将其附加到另一个相同格式的列表中
- spring-boot - 需要帮助了解 OAuth2
- azure - azure 自定义视觉模型精度
- jquery - Oracle Apex 5.1 动态日期选择器 minDate 移动日历图标
- salesforce-lightning - 如何将按钮移动到销售人员闪电组件的中心
- css - 为不同品牌编写 CSS
- three.js - 有没有办法使用 WebGL 和 Three.js 获取深度值?
- java - 如何设置不需要凭据的 Localstack 容器?