我在react js中创建了登录页面,在节点js中创建了api。我试图使用电子邮件和密码登录使用redux。
登录页
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const dispatch = useDispatch();
const navigate = useNavigate();
const { user, isError, isSuccess, isLoading, message } = useSelector(
(state) => state.auth
);
useEffect(() => {
if (user || isSuccess) {
navigate("/dashboard");
}
dispatch(reset());
}, [user, isSuccess, dispatch, navigate]);
const Auth = (e) => {
e.preventDefault();
dispatch(LoginUser({ email, password }));
};
return (
<div className="wrapper">
<main className="authentication-content">
<div className="container-fluid">
<div className="authentication-card">
<div className="card shadow rounded-0 overflow-hidden">
<div className="row g-0">
<div className="col-lg-6 bg-login d-flex align-items-center justify-content-center">
<img src="assets/images/error/login-img.jpg" className="img-fluid" alt=""/>
</div>
<div className="col-lg-6">
<div className="card-body p-4 p-sm-5">
<h5 className="card-title">Sign In</h5>
<p className="card-text mb-5">See your growth and get consulting support!</p>
<form onSubmit={Auth} className="form-body">
{isError && <p className="has-text-centered">{message}</p>}
<div className="row g-3">
<div className="col-12">
<label htmlFor="inputEmailAddress" className="form-label">Email Address</label>
<div className="ms-auto position-relative">
<div className="position-absolute top-50 translate-middle-y search-icon px-3"><i className="bi bi-envelope-fill"></i></div>
<input type="email" value={email} onChange={(e) => setEmail(e.target.value)} className="form-control radius-30 ps-5" id="inputEmailAddress" placeholder="Email Address"/>
</div>
</div>
<div className="col-12">
<label htmlFor="inputChoosePassword" className="form-label">Enter Password</label>
<div className="ms-auto position-relative">
<div className="position-absolute top-50 translate-middle-y search-icon px-3"><i className="bi bi-lock-fill"></i></div>
<input type="password" value={password} onChange={(e) => setPassword(e.target.value)} className="form-control radius-30 ps-5" id="inputChoosePassword" placeholder="Enter Password"/>
</div>
</div>
<div className="col-6">
<div className="form-check form-switch">
<input className="form-check-input" type="checkbox" id="flexSwitchCheckChecked" />
<label className="form-check-label" htmlFor="flexSwitchCheckChecked">Remember Me</label>
</div>
</div>
<div className="col-6 text-end"> <a href="authentication-forgot-password.html">Forgot Password ?</a>
</div>
<div className="col-12">
<div className="d-grid">
<button type="submit" className="btn btn-primary radius-30">{isLoading ? "Loading..." : "Sign In"}</button>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</main>
</div>
)
}
export default Login;在呈现登录页面时,它在null和false中以user和isSuccess显示。当我点击Sign In按钮。它在一秒内显示仪表板,然后重定向到登录页面,并在user和isSuccess中显示isSuccess。当我点击5到10次,然后一旦它显示响应,并坚持在仪表板上。
AuthSlice文件
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from "axios";
const initialState = {
user: null,
isError: false,
isSuccess: false,
isLoading: false,
message: ""
}
export const LoginUser = createAsyncThunk("user/LoginUser", async(user, thunkAPI) => {
try {
const response = await axios.post('http://localhost:5001/login', {
email: user.email,
password: user.password
});
return response.data;
} catch (error) {
if(error.response){
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
});
export const getMe = createAsyncThunk("user/getMe", async(_, thunkAPI) => {
try {
const response = await axios.get('http://localhost:5001/me');
return response.data;
} catch (error) {
if(error.response){
const message = error.response.data.msg;
return thunkAPI.rejectWithValue(message);
}
}
});
export const LogOut = createAsyncThunk("user/LogOut", async() => {
await axios.delete('http://localhost:5001/logout');
});
export const authSlice = createSlice({
name: "auth",
initialState,
reducers:{
reset: (state) => initialState
},
extraReducers:(builder) =>{
builder.addCase(LoginUser.pending, (state) =>{
state.isLoading = true;
});
builder.addCase(LoginUser.fulfilled, (state, action) =>{
state.isLoading = false;
state.isSuccess = true;
state.user = action.payload;
});
builder.addCase(LoginUser.rejected, (state, action) =>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
// Get User Login
builder.addCase(getMe.pending, (state) =>{
state.isLoading = true;
});
builder.addCase(getMe.fulfilled, (state, action) =>{
state.isLoading = false;
state.isSuccess = true;
state.user = action.payload;
});
builder.addCase(getMe.rejected, (state, action) =>{
state.isLoading = false;
state.isError = true;
state.message = action.payload;
})
}
});
export const {reset} = authSlice.actions;
export default authSlice.reducer;仪表板页
const Dashboard = () => {
const dispatch = useDispatch();
const navigate = useNavigate();
const { isError } = useSelector((state) => state.auth);
useEffect(() => {
dispatch(getMe());
}, [dispatch]);
useEffect(() => {
if (isError) {
navigate("/");
}
}, [isError, navigate]);
return (
<Layout>
<Welcome />
</Layout>
);
};
export default Dashboard;发布于 2022-10-03 16:03:59
从登录组件中删除useEffect并更新Auth函数,如
const Auth = (e) => {
e.preventDefault();
dispatch(LoginUser({ email, password }))
.unwrap() // <-- async Thunk returns a promise, that can be 'unwrapped')
.then(() => navigate("/dashboard"))
};解释:在使用createAsyncThunk API时,返回的函数在默认情况下是预先化的。您可以使用using ()方法等待承诺解析(我猜是由Rust (我猜是…)完成的)。当承诺被解决后,它可以被更多的连接起来,然后()调用,这样您就可以从那里导航。
Refference:useNavigate blocks rest of the content in createAsyncThunk, redux toolkit
https://stackoverflow.com/questions/73936916
复制相似问题