Попробуйте перенаправить пользователей на разные страницы по их ролям с помощью маршрутизатора react

#reactjs #react-router

Вопрос:

Поэтому после того, как пользователь вошел в систему, getProfile() вызывается, чтобы получить информацию об их профиле.
и по их роли пользователи будут переходить к user page или admin page .
Для этого я создал ProtectedRoute компонент.
Но каждый user page и admin page не отображается, когда я использую этот компонент.
(отображается только белый экран.)
Я проверил getProfile() , что компонент в ProtectedRoute хорошо получает результат.
но кажется <Layout {...props} /> , что это или <AdminLayout {...props} /> не отображается.
Вот коды.

protectedRoute.js : Отфильтруйте пользователей по их ролям и перейдите к соответствующей странице.

 import React, {useEffect} from 'react';
import {BrowserRouter as Router, Switch, Route, Redirect} from 'react-router-dom';
import Layout from './layouts/layout';
import AdminLayout from './layouts/adminLayout';
import {useDispatch} from 'react-redux';
import {getProfile} from './data_actions/userInfo_action/userInfo_action';
import {unwrapResult} from '@reduxjs/toolkit';
import {useHistory} from 'react-router-dom';

export const ProtectedRoute = ({component: Component, admin = null, ...rest}) => {
  const dispatch = useDispatch();
  return (
    <Route
      {...rest}
      path={rest.path}
      render={(props) => {
        dispatch(getProfile())
          .then(unwrapResult)
          .then((res) => {
            if ((res.role === 'PRO' || res.role === 'CLIENT') amp;amp; !admin) {
              <Layout {...props} />;
            } else if (res.role === 'ADMIN' amp;amp; admin) {
              <AdminLayout {...props} />;
            }
          })
          .catch((err) => {
            return (
              <Redirect
                to={{
                  pathname: '/',
                  state: {
                    from: props.location,
                  },
                }}
              />
            );
          });
      }}
    />
  );
};
 

App.jsx : Где размещен компонент protectedRoute.

 import React, {useContext, useEffect, useRef, useState} from 'react';
import Layout from './layouts/layout';
import AdminLayout from './layouts/adminLayout';
import './App.scss';
import {BrowserRouter as Router, Switch, Route, Redirect} from 'react-router-dom';
import LoginPage from '@/pages/user/sign/login';
import NotFound from './pages/notFound';
import {ProtectedRoute} from './protectedRoute';

function App() {

  return (
    <Router>
      <Switch>
        {/* login */}
        <Route exact path={`/fn/sign/login`} render={(props) => <LoginPage {...props} />} />
   
        <ProtectedRoute exact path={`${process.env.PUBLIC_URL}`} component={Layout} admin={false} />
        <ProtectedRoute
          exact
          path={`${process.env.PUBLIC_URL}/admin`}
          component={AdminLayout}
          admin={true}
        />
        <Route path="*" component={NotFound} />
      </Switch>
    </Router>
  );
}

export default App;
 

layout.jsx : Layout Component that contains user’s router.

 import React, {memo, useContext, useEffect} from 'react';
import PropTypes from 'prop-types';
import Drawer from '@material-ui/core/Drawer';
import Hidden from '@material-ui/core/Hidden';
import {makeStyles, useTheme} from '@material-ui/core/styles';
import SideBar from './sidebar';
import './layout.scss';
import Router from '../routes/router';

const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
  },

  toolbar: {
    [theme.breakpoints.up(theme.breakpoints.values.md)]: {
      display: 'none',
    },
  },
  content: {
    width: '100%',
    flexGrow: 1,
  },
}));

function Layout(props) {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <nav className={classes.drawer}>
        <Hidden mdDown implementation="css">
          <Drawer
            className={classes.drawer}
            classes={{
              paper: classes.drawerPaper,
            }}
            variant="permanent"
            open
          >
            <SideBar />
          </Drawer>
        </Hidden>
      </nav>
      <main className={classes.content}>
        <div className={classes.toolbar} />
        <Router {...props} />
      </main>
    </div>
  );
}

Layout.propTypes = {
  window: PropTypes.func,
};

export default memo(Layout);
 

router.js : страницы пользователя

 import React, {useEffect} from 'react';
import {Switch, Route, Redirect} from 'react-router-dom';
import JobList from '@/pages/user/jobNotiBoard/jobList';
import JobDetail from '@/pages/user/jobNotiBoard/jobDetail';
import NotFound from '@/pages/notFound';
import {useDispatch, useSelector} from 'react-redux';
import {setNewCount2} from '@/data_actions/jobNoti_action/newDataCount_action';

function Router(props) {
  const dispatch = useDispatch();
  const newDataCount = useSelector((state) => state.newJobNotiPostCount);
  useEffect(() => {
    dispatch(setNewCount2());
  }, []);

  return (
    <React.Fragment>
      <Switch>
        <Route
          exact
          path={`${process.env.PUBLIC_URL}/joblist`}
          render={(props) => <JobList {...props} newDataCount={newDataCount?.count} />}
        />
        <Route
          path={`${process.env.PUBLIC_URL}/detail/:id/:site`}
          render={(props) => <JobDetail {...props} />}
        />
        <Route path="*" component={NotFound} />
      </Switch>
    </React.Fragment>
  );
}

export default Router;
 

Ответ №1:

Рендеринг prop в вашем ProtectedRoute ничего не возвращает.

Вам придется изменить его на что-то вроде

 export const ProtectedRoute = ({
  component: Component,
  admin = null,
  ...rest
}) => {
  const dispatch = useDispatch();

  const [role, setRole] = React.useState(null);
  React.useEffect(
    () => {
      dispatch(getProfile())
        .then(unwrapResult)
        .then((res) => {
          setRole(res.role);
        })
        .catch((err) => {
          setRole("PROFILE_ERROR");
        });
    },
    [ /* dependencies for when to re-request the profile*/ ]
  );

  return (
    <Route
      {...rest}
      path={rest.path}
      render={(props) => {
        if ((role === "PRO" || role === "CLIENT") amp;amp; !admin) {
          return <Layout {...props} />;
        } else if (role === "ADMIN" amp;amp; admin) {
          return <AdminLayout {...props} />;
        } else if (role === "PROFILE_ERROR") {
          return (
            <Redirect
              to={{
                pathname: "/",
                state: {
                  from: props.location
                }
              }}
            />
          );
        }
      }}
    />
  );
};