提问人:Oussema Sahbeni 提问时间:11/16/2023 更新时间:11/16/2023 访问量:83
React 无法获取 localStorage init 值
React Failing to get the localStorage init value
问:
大家好,我正在开发一个 mern 应用程序,并且很好奇如何实现 jwt 令牌身份验证,它工作正常,但我前面遇到了一个小问题,用户登录后在 localstorage 上成功设置了令牌,但是当我尝试使用 axios 获取值时,同时在标头中发送令牌, 令牌值在第一次渲染时始终为 null,我必须刷新页面,以便标头从本地存储访问令牌 这是useLogin组件,令牌立即设置在localStorage上
const login = async (email, password) => {
const user = { email, password };
setError(null);
try {
const response = await axios.post(
"http://localhost:4000/api/user/login",
user
);
const result = response.data;
console.log(response);
if (response.statusText === "OK") {
setError(null);
setIsLoading(false);
// save the token in local storage
localStorage.setItem("user", JSON.stringify(result));
// update the dispatch
dispatch({ type: "LOGIN", payload: result });
}
} catch (error) {
const response = error.response.data;
setError(response.message);
//console.log(error);
}
};
这是我的 authContext,我试图获取 localStorage 值
export const AuthContext = createContext();
export const authReducer = (state, action) => {
switch (action.type) {
case "LOGIN":
return { user: action.payload.user };
case "LOGOUT":
return { user: null };
default:
return state;
}
};
export const AuthContextProvider = ({ children }) => {
const initialState = JSON.parse(localStorage.getItem("user")) || null;
const [state, dispatch] = useReducer(authReducer, { user: initialState });
// useEffect(() => {
// //check if there is a token in local storage
// const user = JSON.parse(localStorage.getItem("user"));
// console.log(user);
// if (user !== undefined && user !== null) {
// dispatch({ type: "LOGIN", payload: { user } });
// }
// }, []);
console.log("authContext state", state);
return (
<AuthContext.Provider value={{ ...state, dispatch }}>
{children}
</AuthContext.Provider>
);
};
我尝试使用useEffect,它导致了同样的问题,getItem(“user”)在第一次渲染时总是为null,并且在我刷新页面后工作正常
最后是 IM 尝试获取数据的 Home 组件
user.token 变量在第一次渲染时始终未定义,但在我刷新时工作正常
import axios from "axios";
import { useWorkoutContext } from "../hooks/useWorkoutContext";
import { useAuthContext } from "../hooks/useAuthContext";
// component
import WorkoutDetails from "../components/workoutDetails";
import WorkoutForm from "../components/workoutForm";
const Home = () => {
// const [workouts, setWorkouts] = useState([]);
const { workouts, dispatch } = useWorkoutContext();
const [error, setError] = useState(null);
const { user } = useAuthContext();
useEffect(() => {
const fetchWorkouts = async () => {
console.log(user.token);
try {
if (user && user.token) {
const response = await axios.get(
"http://localhost:4000/api/workouts",
{
headers: {
Authorization: `Bearer ${user.token}`,
},
}
);
const result = response.data;
if (response.status === 200) {
// console.log(result);
// setWorkouts(result);
dispatch({ type: "SET_WORKOUTS", payload: result });
}
}
} catch (error) {
console.error("Error fetching workouts:", error);
setError("Error fetching workouts. Please check your network.");
}
};
//console.log(user);
if (user) {
fetchWorkouts();
}
}, [dispatch, user]);
return (
<div className="home">
<div className="workouts">
{workouts &&
workouts.map((workout) => {
return <WorkoutDetails key={workout._id} workout={workout} />;
})}
{error && <p>{error}</p>}
</div>
<WorkoutForm />
</div>
);
};
export default Home;
这是我的 Back requireAuth express 代码
import { userModel } from "../models/userModel.js";
const requireAuth = async (req, res, next) => {
// verify authentication
// we get authorization from the headers
const { authorization } = req.headers;
console.log(authorization);
if (!authorization) {
res.status(401).json({ error: "authorization required" });
}
// authorization is a string that contains the token
let token;
if (authorization) {
token = authorization.split(" ")[1];
console.log("Token is " + token);
}
try {
// returns the id of the user that is in the token
const { _id } = jwt.verify(token, process.env.SECRET);
console.log("id is " + _id);
req.user = await userModel.findOne({ _id }).select("_id");
next();
} catch (error) {
console.log(error);
res.status(401).json({ error: "request is not authorized" });
}
};
export default requireAuth;
我现在坚持了 2 天:'((
答:
之所以发生这种情况,是因为您的响应由 和 object 组成。将整个响应存储在本地存储中,因此存储由 和 组成的对象。但是,当您处理该事件时,您只存储来自响应的对象和其他两个键(并被丢弃)。email
token
user
email
token
user
LOGIN
user
email
token
在调度 LOGIN 事件后的第一次渲染中,您尝试访问密钥,但它不在用户对象中 - 它在用户对象之外,并且您尚未将其保存在 reducer 中。token
刷新页面时,将解析本地存储中的内容,在初始状态下,您将获得整个响应,包括 和 对象。当您使用解析的对象并请求值时,现在可以访问它。email
token
user
token
您需要进行以下更改:
export const authReducer = (state, action) => {
switch (action.type) {
case "LOGIN":
return { user: action.payload}; // save the whole payload instead of just the user object (action.payload.user)
case "LOGOUT":
return { user: null };
default:
return state;
}
};
评论