我有问题,我的登录功能在我的前端。我确信这是在我的前端造成的,因为在 Postman 中,我所有的数据流都工作正常。
我有一个登录组件,它从表单中捕获电子邮件和密码,并使用数据调度一个操作:
import React, { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux';
import { loginUser } from '../../slices/authSlice';
import '../../styles/components/Auth/LoginForm.css';
import { BrowserRouter , Navigate } from 'react-router-dom';
const LoginForm = () => {
const dispatch = useDispatch();
const [formData, setFormData] = useState({
email: "",
password: ""
});
const {email, password } = formData;
const onChange = (e) =>
setFormData({ ...formData, [e.target.name]: e.target.value });
const onSubmit = (e) => {
e.preventDefault();
dispatch(loginUser({email, password}));
};
return (
<form action="" className="login__form" onSubmit={(e) => onSubmit(e)}>
<div className="field-container">
<label>Email</label>
<input
type="email"
name="email"
value={email}
onChange={(e) => onChange(e)}
/>
</div>
<div className="field-container">
<label>Password</label>
<input
type="password"
name="password"
id=""
value={password}
onChange={(e) => onChange(e)}
/>
</div>
<button type="submit">Log In</button>
</form>
);
};
export default LoginForm;
后来我有我的authSlice与不同的方法:
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import axios from 'axios';
import setAuthToken from "../utils/setAuthToken";
const initialState = {
token: localStorage.getItem('token'),
isAuthenticated: false,
isLoading: true,
user: null
}
export const loadUser = createAsyncThunk(
'auth/loadUser',
async (_,{ rejectWithValue }) => {
if(localStorage.token){
setAuthToken(localStorage.token);
}
try {
const res = await axios.get('http://localhost:5000/api/auth/me');
return res.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
)
export const registerUser = createAsyncThunk(
'auth/registerUser',
async (newUser, { dispatch, rejectWithValue }) => {
try {
const config = {
headers: {
'Content-Type': 'application/json',
},
};
const body = JSON.stringify(newUser);
const response = await axios.post(
'http://localhost:5000/api/auth/register',
body,
config
);
dispatch(loadUser(newUser));
return response.data;
} catch (error) {
return rejectWithValue(error.response.data);
}
}
);
export const loginUser = createAsyncThunk('auth/login', async ({ email, password }, { dispatch, rejectWithValue }) => {
const body = { email, password };
const config = {
headers: {
'Content-Type': 'application/json',
},
};
try {
const res = await axios.post('http://localhost:5000/api/auth/login', body, config);
dispatch(loadUser(res.data));
console.log(body)
return res.data;
} catch (err) {
return rejectWithValue(err.response.data);
}
});
export const authSlice = createSlice({
name: 'auth',
initialState,
reducers:{
logout:(state, action) => {
state.token = null;
localStorage.removeItem('token');
state.isAuthenticated = false;
state.user = null;
}
},
extraReducers: (builder) => {
builder
.addCase(loadUser.pending, (state) => {
state.isLoading =true;
})
.addCase(loadUser.fulfilled, (state, action) => {
state.isLoading = false;
state.isAuthenticated = true;
state.user = action.payload;
})
.addCase(loadUser.rejected, (state, action) => {
state.isLoading = false;
state.isAuthenticated = false;
console.log(action.payload);
})
.addCase(registerUser.pending, (state) => {
state.isLoading = true;
})
.addCase(registerUser.fulfilled, (state, action) => {
state.token = localStorage.setItem('token', action.payload.token);
state.isLoading = false;
state.isAuthenticated = true;
state.user = action.payload;
})
.addCase(registerUser.rejected, (state, action) => {
state.isLoading = false;
/* state.isAuthenticated = false; */
console.log(action.payload);
})
.addCase(loginUser.pending, (state) => {
state.isLoading = true;
})
.addCase(loginUser.fulfilled, (state, action) => {
state.isAuthenticated = true;
state.isLoading = false;
state.user = action.payload;
state.token = localStorage.setItem('token', action.payload.token);
})
.addCase(loginUser.rejected, (state, action) => {
state.isAuthenticated = false;
state.isLoading = false;
state.user = null;
console.log(action.error);
}
)
}
});
export const { logout } = authSlice.actions;
export default authSlice.reducer;
这是我的util函数setAuthToken.js:
import axios from 'axios';
const setAuthToken = (token) => {
if (token) {
axios.defaults.headers.common['Authorization'] = `Bearer ${token}`;
} else {
delete axios.defaults.headers.common['Authorization'];
}
console.log(axios.defaults.headers.common['Authorization']);
};
export default setAuthToken;
问题如下。当我在我的redux devtools中提交表单时,我得到了正确的数据auth/login/fullfilled。但auth/loaduser被拒绝,并获取以下数据:
type(pin):"auth/loadUser/rejected"
success(pin):false
error(pin):"Not authorized to access this route"
success(pin):true
token(pin):"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVkNzEzOTk1YjcyMWMzYmIzOGMxZjVkNSIsImlhdCI6MTY4NjA4NDA0MiwiZXhwIjoxNjg2MDg1MDQyfQ.QorBCHQW5QBXdQHG0HD3fXLWsWX3aOVQyD8uKmEZMoI"
requestId(pin):"NLUh3rFIYsFilYjBGkbmK"
rejectedWithValue(pin):true
requestStatus(pin):"rejected"
aborted(pin):false
condition(pin):false
message(pin):"Rejected"
我不知道为什么我被拒绝,如果令牌是有效的。
所以我的登录有bug。
在第一次登录中,我得到了auth/login/fullfillled和auth/loaduser/rejected,但令牌在我的本地存储中设置正确。
现在,如果我尝试再次登录,令牌已经设置,我得到两个操作都已完成。
为什么我在第一次得到auth/login/fulfilled和auth/loaduser/rejected?
1条答案
按热度按时间xzlaal3s1#
loginUser
操作不会设置任何令牌值、状态或localStorage中的任何内容。***将token值设置为state/localStorage的是loginUser.fulfilled
操作,特别是在处理它的reducer函数中。这是对Redux reducer函数的一种相当无效的使用,尽管reducer函数应该是纯粹的,没有副作用,无论是有意还是无意的。这意味着虽然loginUser
仍在处理并分派loadUser(res.data)
,但Redux状态尚未更新。这意味着localStorage也没有更新。这里我的建议是将localStorage更新移动到Thunk中,在那里异步和副作用逻辑更合适。