简体   繁体   English

PrivateRoute 在刷新页面时总是重定向到登录页面; 如何等待 useEffect() 和 localStorage?

[英]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.

相关问题 当我使用 PrivateRoute 时,我总是在重新加载页面时 go 到登录页面一次 - When I use PrivateRoute, I always go to the login page once when I reload the page 刷新页面时,基于 API 调用的 React Hooks PrivateRoute 不起作用 - React Hooks PrivateRoute based on API call don't work when refreshing the page React - 刷新时始终到初始页面 - React - When refreshing getting always to initial page Redux、localStorage 和 React:刷新页面时出错 - Redux, localStorage, and React: Getting an error when refreshing my page 刷新页面后 localStorage 值设置为 undefined - localStorage values are set to undefined after refreshing the page react router v5 privateroute 登录并刷新页面后进入登录 - react router v5 privateroute goes to login after logging in and refreshing page 页面重新加载时如何使用useEffect deps? - How to use useEffect deps when page reload? 如何在页面可见时重新运行 useEffect? - How to rerun useEffect when page is visible? 在 PrivateRoute 中重定向不呈现我的页面 - Redirect in PrivateRoute not render my page useEffect 中的套接字连接事件在创建组件时不起作用,但在 React 中刷新页面后起作用 - socket connect event inside useEffect does not work when component is created but works after refreshing the page in React
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM