[英]PrivateRoute always redirects to sign in page when refreshing the page; How to wait for useEffect() and localStorage?
I am implementing security and user management in my application and ran into an issue with react router, Context, localStorage.我正在我的应用程序中实现安全性和用户管理,并遇到了反应路由器、上下文、localStorage 的问题。
With router, I have created a private route and I check if the userID exists on Context or localStorage, if userID does not exist then I re-direct the user to the sign in page.使用路由器,我创建了一条私有路由,并检查用户 ID 是否存在于 Context 或 localStorage 上,如果用户 ID 不存在,则我将用户重定向到登录页面。 This works great, BUT if I refresh the page, it ALWAYS redirects to the sign in page.
这很好用,但是如果我刷新页面,它总是会重定向到登录页面。 Even though the user is logged in, and should exist on localStorage.
即使用户已登录,并且应该存在于 localStorage。
I think the issue stems from localStorage and "useEffect()".我认为问题源于 localStorage 和“useEffect()”。 My theory is that the router redirects BEFORE localStorage (and useEffect) is done checking if the userID exists.
我的理论是,在 localStorage(和 useEffect)检查用户 ID 是否存在之前,路由器会重定向。 Not sure how I can go around this?
不知道我怎么能解决这个问题?
Here's the code for my Private Route component"这是我的 Private Route 组件的代码”
import {
Route,
Redirect,
RouteProps,
} from 'react-router-dom';
import {MyContextProvider, useMyContext} from '../Context/UserContext';
interface PrivateRouteProps extends RouteProps {
// tslint:disable-next-line:no-any
component: any;
UserID: number;
}
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, UserID, ...rest } = props;
console.log("Inside Route: "+ UserID);
return (
<Route
{...rest}
render={(routeProps) =>
UserID > 0 ? (
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: routeProps.location }
}}
/>
)
}
/>
);
};
export default PrivateRoute;
^ The " console.log("Inside Route: "+ UserID); " prints a 0, so thats why it always redirects to sign in page. ^ "console.log("Inside Route: "+ UserID);" 打印一个 0,所以它总是重定向到登录页面。 This is why I think the useEffect() (shown below in routing) may have something to do with userID not being set properly.
这就是为什么我认为 useEffect()(如下所示的路由)可能与未正确设置用户 ID 有关。
Code for Routing part:路由部分的代码:
function Routing() {
const classes = useStyles();
const [store, setStore] = useMyContext();
useEffect(() => { // check if user exists in localstorage, if so, set the values on react Context
const res = localStorage.getItem("UserID");
if (res) {
// since LocalStorage can return a type or null, we must check for nulls and set accordingly.
const uID = localStorage.getItem("UserID");
const UserID = uID !== null ? parseInt(uID) : 0;
const un = localStorage.getItem("Username");
const Username = un !== null ? un : '';
const iA = localStorage.getItem("IsAdmin");
const isAdmin = iA != 'true' ? true : false;
const eN = localStorage.getItem("EmailNotifications");
const emailNotifications = eN != 'true' ? true : false;
setStore({ // update the 'global' context with the logged in user data
UserID:UserID,
Username: Username,
IsAdmin: isAdmin,
EmailNotifications: emailNotifications
});
console.log(UserID);
console.log(Username);
console.log(isAdmin);
console.log("foundUser");
}
}, []);
const id = store.UserID; // get the userID from context; to pass into PrivateRoute
console.log("ID: ++"+ id);
return (
<div className="App">
<Router>
<Switch>
<Route exact path="/" component={Login}/>
<PrivateRoute path="/dashboard" UserID={id} component={Dashboard}/>
<PrivateRoute path="/add" UserID={id} component={AddTicket}/>
<PrivateRoute path="/settings" UserID={id} component={Settings}/>
<Route component={NotFound}/>
</Switch>
</Router>
</div>
);
}
export default Routing;
To solve for what I wanted to accomplish, I just added the localStorage retrieval directly inside PrivateRoute (instead of the parent node of PrivateRoute with useEffect)为了解决我想要完成的事情,我只是在 PrivateRoute 中直接添加了 localStorage 检索(而不是使用 useEffect 的 PrivateRoute 的父节点)
const PrivateRoute = (props: PrivateRouteProps) => {
const { component: Component, UserID, ...rest } = props;
console.log("Inside Route: "+ UserID);
return (
<Route
{...rest}
render={(routeProps) =>
localStorage.getItem("UserID") ? ( // if UserID == 0 when user is NOT logged in. So, if ID == 0, redirect to signinpage
<Component {...routeProps} />
) : (
<Redirect
to={{
pathname: '/',
state: { from: routeProps.location }
}}
/>
)
}
/>
);
}; };
Storing the user's id in storage is very bad idea.将用户的 id 存储在存储中是非常糟糕的主意。 This is sensitive information.
这是敏感信息。 Try to implement logic which will display a spinner or HTML skeleton while waiting to fetch the id from your your server or whoever server you are using.
在等待从您的服务器或您正在使用的任何服务器获取 id 时,尝试实现将显示微调器或 HTML 骨架的逻辑。 The URL might change for a bit but the user will see only the spinner/HTML skeleton and this is way better UX than redirecting and show pages the user shouldn't see, not to mention the user's id saving in the storage.
URL 可能会发生一些变化,但用户只会看到微调器/HTML 骨架,这比重定向和显示用户不应该看到的页面更好的用户体验,更不用说保存在存储中的用户 ID。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.