【问题标题】:React Router based on dynamic context values基于动态上下文值的 React Router
【发布时间】:2020-07-02 21:34:25
【问题描述】:

我希望你一切都好。

我正在开发一个 react(typescript) 应用程序,我必须在其中处理身份验证和授权。

我正在遵循这种模式。 IAuthContext(将在启动期间或用户更改状态时加载)

export interface IAuthContext {
    isAuthenticated: boolean;
    isInitialized: boolean;
    user: firebase.User | null;
    permissions: object;
    landingPage: string;
    isOnBoardingCompleted: boolean;
}

Routes.js

const routerConfig = [
    {
        key: "key_",
        path: '/login',
        component: Login,
        isPrivate : false
    },
    {
        key: "dashboard",
        path: '/dashboard',
        component: Frame,
        content: AnalyticsDashBoard,
        isPrivate : true
    },

App.tsx

return (
        <BrowserRouter>
            <div>
                <Switch>
                    {routes.map((route) =>{
                        return (route.isPrivate ?
                            <PrivateRoute {...route} exact/>
                            :
                            <Route path={route.path} component={route.component} key={route.key} exact/>)
                    })}
                </Switch>
            </div>
        </BrowserRouter>
    );

PrivateRoute.tsx

return (
        <Route
            {...rest}
            render={(routeProps) =>
                props.context.isAuthenticated ? (
                    <Component {...routeProps} content={props.content}/>
                ) : (
                    <Redirect
                        to={{
                            pathname: '/login',
                            state: { from: routeProps.location }
                        }}
                    />
                )
            }
        />
    );

在 privateRoute 中,我可以访问角色和权限以及登录页面(如果用户在登录后没有完成注册,他必须被重定向到注册页面)。此外,我需要根据身份验证在私有路由中提供所有可能的组合,因为它只会加载一次。

我试图在私人路线中这样做

if (props.context.isAuthenticated && !props.context.isOnBoardingCompleted) {
        console.log("Going to redirect here to onboard--", props.context.landingPage);
        return <Route path={props.context.landingPage} component={OnBoarding}/>
    }

但这不起作用,因为只有 URL 发生了变化。此外,如果用户完成了入职,我可能没有路由,因为所有路由器控件都已使用首次值创建。 请告诉我如何处理这个问题?我需要做的就是拥有某种拦截器,我可以在其中根据动态上下文值路由/重定向到页面。

期望: 就像上面的场景一样,有多个角色和权限,所有这些条件都应该在这里检查。

【问题讨论】:

    标签: reactjs typescript react-router


    【解决方案1】:

    &lt;Route path={props.context.landingPage} component={OnBoarding}/&gt; 应该在您的Router 组件中定义。

    您可以使用嵌套的三元组,但这会导致可读性问题。

    return (
      <Route
        {...rest}
        render={routeProps =>
          props.context.isAuthenticated ? (
            props.context.isOnBoardingCompleted ? (
              <Component {...routeProps} content={props.content} />
            ) : (
              <Redirect
                to={{
                  pathname: "/landing", // or "/onboard" whatever the route is
                  state: { from: routeProps.location }
                }}
              />
            )
          ) : (
            <Redirect
              to={{
                pathname: "/login",
                state: { from: routeProps.location }
              }}
            />
          )
        }
      />
    );
    

    【讨论】:

    • 我想到了类似的解决方案,但如果我没记错的话,这个路由会根据当前上下文值在启动时加载一次。一旦上下文发生变化,就不再需要进行入职培训,但我们没有为该组合定义路线。
    • Router 是否有权访问此“上下文”,以便在需要时根据isOnBoardingCompleted 有条件地渲染此“/onboard”路由?否则,您似乎将通用 UI 组件与特定应用程序用例进行了一些不健康的耦合。 always 渲染“/onboard”路线有什么问题吗?对于任何用户来说,它有什么特别和内在的东西吗?在您的示例中似乎不是基于它的 API,因为您只是想重定向到它。
    • 道歉,因为我没有完全理解你的陈述。但关键是我需要一种拦截器/基于上下文值的东西,我需要适当地控制加载。即,一旦用户完成入职,下次他可以被重定向到所需的页面,如果他无权访问所需的页面,他可以被重定向到他的登录页面。我希望你明白这一点。
    • 根据给出的细节,这正是上面的代码应该做的。如果这不是您想要的行为,您可以通过更多相关的应用设置来更新您的问题吗?路由器、应用程序状态/上下文等。
    • @DrewReese 这是我的问题:stackoverflow.com/q/68573847/16334669
    【解决方案2】:

    也许你可以像下面这样组织你的代码。它将帮助您分离不同的路由并以清晰易读的方式处理它们的角色/身份验证检查。

    
    function App() {
      return (
          <BrowserRouter>
            <div>
              <Switch>
                <Route component={PublicContainer}/>
                <Route component={PrivateContainer}/>
              </Switch>
            </div>
          </BrowserRouter>
      );
    }
    
    const PrivateContainer = () => (
      <div>
        <NavBar/>
        <Switch>
          //routes with auth checks
        </Switch>
      </div>
    );
    
    
    const PrivateContainer = () => (
      <div>
        <NavBar/>
        <Switch>
          //Free routes
        </Switch>
      </div>
    );
    

    【讨论】:

      猜你喜欢
      • 2017-07-17
      • 1970-01-01
      • 2023-02-24
      • 2017-04-28
      • 1970-01-01
      • 1970-01-01
      • 2019-07-27
      • 2018-09-03
      • 2019-10-23
      相关资源
      最近更新 更多