目标:-
我希望用户仅在登录后才能看到他/她的订单。因此,我正在使用AuthContext对登录数据和令牌的用户进行状态管理。
问题:-
当我将令牌从AuthContext传递到子组件时,AuthContext需要花费一些时间来验证后端的令牌,同时子组件的逻辑中断。
子组件(使用状态/令牌):
const MyOrders = () => {
const { userData } = useContext(AuthContext);
const history = useHistory();
if (!userData.token) { // This redirects the user back to the home page immediately
history.push("/"); // because the token hasn't been passed yet when
// the component is loaded
};
const getOrders = async () => {
const url = 'http://localhost:5000/api/orders';
try {
const res = await axios.get(url, {
headers: {
'x-auth-token': userData.token
}
});
console.log(res.data);
} catch (err) {
console.log(err.response);
}
};
useEffect(() => {
if (userData.token) getOrders();
}, []);
解决(安全吗???)
const MyOrders = () => {
const token = localStorage.getItem('auth-token'); // Use localStorage token directly instead of
// validating the token first (from AuthContext)??
const history = useHistory();
if (!token) {
history.push("/");
};
const getOrders = async () => {
const url = 'http://localhost:5000/api/orders';
try {
const res = await axios.get(url, {
headers: {
'x-auth-token': token
}
});
console.log(res.data);
} catch (err) {
console.log(err.response);
}
};
useEffect(() => {
if (userData.token) getOrders();
}, []);
父组件(AuthContext): // //如果有人需要
const AuthContextProvider = (props) => {
const [userData, setUserData] = useState({
token: undefined,
user: undefined
});
//Need to check if user is logged in
//every time the App is rendered
useEffect(() => {
const checkLoggedIn = async () => {
const url = "http://localhost:5000/api/users/token";
let token = localStorage.getItem("auth-token");
//when user is not logged in
if(token === null) {
localStorage.setItem("auth-token", "");
token = "";
}
//need to validate the token if it exists
const tokenResponse = await axios.post(url, null, {
headers: { "x-auth-token": token }
});
//if token is valid, collect user data
if(tokenResponse.data){
console.log(tokenResponse);
setUserData({
token,
user: tokenResponse.data,
});
} else {
localStorage.setItem("auth-token", "");
token = "";
};
};
checkLoggedIn();
}, []);
答案 0 :(得分:0)
也许您可以尝试在history.push(“ /”)之后尽早返回,以便其余逻辑不会执行
const MyOrders = () => {
const { userData } = useContext(AuthContext);
const history = useHistory();
if (!userData.token) { // This redirects the user back to the home page immediately
history.push("/");
return (null)
};
const getOrders = async () => {
const url = 'http://localhost:5000/api/orders';
try {
const res = await axios.get(url, {
headers: {
'x-auth-token': userData.token
}
});
console.log(res.data);
} catch (err) {
console.log(err.response);
}
};
useEffect(() => {
if (userData.token) getOrders();
}, []);
答案 1 :(得分:0)
我为您提供尝试在应用程序第一页中检索保存的令牌的功能。 在功能上使用“等待”。尝试从localStorage检索完成后, 如果令牌不存在,则应导航至登录名,否则应导航至主页。 在这种情况下,如果您有令牌,就不会有未定义的令牌,
但是,如果令牌以某种方式未定义怎么办?如果用户尝试使用未定义的令牌进行获取,则需要从服务器发送未授权错误,然后在客户端捕获错误,检查消息和收到的类型,如果确实发生授权错误,请导航至首页页面。
这是一个有点复杂的答案,但它肯定可以解决您的问题,并且将使它变得更简洁和更简洁。
答案 2 :(得分:0)
您可以向用户数据中添加加载,如果设置用户数据失败,则将加载设置为false,您可以通过从react-router返回一个Redirect组件来按订单进行重定向。
const AuthContext = React.createContext();
const AuthContextProvider = ({ children }) => {
const [userData, setUserData] = React.useState({
token: undefined,
user: undefined,
loading: true,
});
React.useEffect(() => {
setTimeout(
() =>
setUserData((userData) => ({
...userData, //any other data that may be there
token: 123,
user: 'Hello world',
loading: false, //not loading anymore
})),
5000 //wait 5 seconds to set user data
);
}, []);
return (
<AuthContext.Provider value={userData}>
{children}
</AuthContext.Provider>
);
};
const App = () => {
const { loading, ...userData } = React.useContext(
AuthContext
);
if (!loading && !userData.token) {
//snippet does not have redirect
// but if you have react-router you
// can do this
//return <Redirect to="/" />;
}
React.useEffect(() => {}, []);
return loading ? (
'loading...'
) : (
<pre>{JSON.stringify(userData, undefined, 2)}</pre>
);
};
ReactDOM.render(
<AuthContextProvider>
<App />
</AuthContextProvider>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>