Могу ли я использовать компоненты частного маршрута более высокого порядка внутри коммутатора в React Router? - PullRequest
2 голосов
/ 28 июня 2019

Я пытаюсь настроить Router для использования пользовательских PrivateRoute компонентов, которые эквивалентны примеру , приведенному в официальных документах react-router.Подвох в том, что я также хочу использовать универсальный маршрут 404, поэтому я думаю, что мне нужно также использовать компонент Switch, как показано в этом примере из документов.

Здесь есть конфликт, потому что документы для Switch указывают, что дочерние элементы Switch компонента должны быть Route компонентами, а в этой проблеме команда заявляет, чтоиспользование компонентов вне маршрута внутри Switch не поддерживается, даже если это работает.

Я создал маршруты более высокого порядка и в настоящее время использую их внутри Switch, и, похоже, он работает, но это не пройдет проверку кода в моей компании, поскольку она использует неподдерживаемый API, который может сломаться в любое время.Я хочу знать, есть ли полностью поддерживаемый способ использовать маршруты более высокого порядка вместе с универсальным маршрутом.

Я пытаюсь создать маршрут 404 без необходимости использовать Switch или использовать обычные Route компоненты, но вместо этого обернуть компонент, переданный Route в логику аутентификации.

import { Router, Route, Switch } from 'react-router-dom';

// Array of authorization functions to be tested by private routes
const authCriteria = [
  // The next route must have been referred by a previous route
  props => defined(props.location.state.from),
];

// Seems to work as expected, but violates the supported use 
// of the Switch component
const AppRouter = () => {
  return (
    <Router>
      <Switch>
        <Route exact path='/' component={Store} />
        <PrivateRoute 
          exact
          path='/account' 
          component={Account}
          authCriteria={authCriteria}
        />
        <PrivateRoute 
          exact
          path='/shipping' 
          component={Shipping} 
          authCriteria={authCriteria}
        />
        <PrivateRoute 
          exact 
          path='/checkout' 
          component={Checkout} 
          authCriteria={authCriteria}
        />
        // Catch-all route means we need to use a Switch
        <Route render={() => (<h2>Not Found</h2>)} />
      </Switch>
    </Router>
  );
};

export default AppRouter;

Ответы [ 2 ]

2 голосов
/ 28 июня 2019

Судя по ссылкам вашего вопроса на github реагирующего маршрутизатора, не похоже, что вы можете использовать HOC внутри Switch.

Однако вы можете добиться чего-то подобного. В основном вам нужны два роутера. Первый Router маршрутизирует все предварительно аутентифицированные маршруты, такие как вход в систему, новые пользователи, забытый пароль и т. Д. Поскольку он находится внутри Switch, он должен отобразить ваш второй Router. Ваш второй Router будет содержать все ваши маршруты, необходимые для аутентификации. Однако вам необходимо включить условную проверку, чтобы убедиться, что пользователь аутентифицирован. Если пользователь не аутентифицирован, вы можете просто вернуть Redirect обратно на путь /login. Это работает из-за первого Switch. Если пользователь переходит по URL-адресу, который недоступен для неаутентифицированных пользователей, он всегда будет перенаправлен на /login, поскольку он достигнет условия по умолчанию в первом переключателе и Redirect второго компонента.

import { Router, Route, Switch } from 'react-router-dom';

const AppRouter = (props) => {
  return (
    <Router>
      <Switch>
        <Route exact path='/login' component={Login} />
        <Route exact path='/new-user' component={CreateAccount} />
        <Route render={props => <AuthenticationRouter {...props} />}
      </Switch>
    </Router>
  );
};

const AuthenticatedRouter = (props) => {
  if( props.userIsAuthenticated ) {
    return (
      <Router>
        <Switch>
          <Route exact path='/' component={Store} />
          <Route 
            exact
            path='/account' 
            component={Account}
          />
          <Route 
            exact
            path='/shipping' 
            component={Shipping} 
          />
          <Route 
            exact 
            path='/checkout' 
            component={Checkout} 
          />
          <Route render={() => (<h2>Not Found</h2>)} />
        </Switch>
      </Router>
    );
  }

  return (
    <Redirect
      to={{
        pathname: "/login",
        state: { from: props.location }
      }}
    />
  );
};

export default AppRouter;
1 голос
/ 29 июня 2019

Обновление: Я изменил свой HoC аутентификации маршрута, чтобы обернуть компонент, отображаемый маршрутом, а не сам маршрут.Первый ответ, который был опубликован, вероятно, был бы лучше, если бы критерии аутентификации были статическими, но приложение, над которым я работаю, представляет собой рабочий процесс размещения заказов, в котором доступ к различным маршрутам может зависеть от различных факторов, например, от завершения или от других маршрутов,поэтому мне нужно было иметь возможность передавать произвольные критерии аутентификации каждому маршруту.

Вот код, который показывает withAuth HoC, который я использовал для обертывания каждого компонента, и как он работает с маршрутизатором:

// Test every passed-in auth verification function.
const verifyAuth = (authCriteria, props) => {
  if (authCriteria.length === 0) return true;
  return authCriteria.every(criterion => criterion(props));
};

// Authentication HoC
const withAuth = ({
  authCriteria = [],
  redirectPath = '/',
} = {}) => Component => props => {
  const isAuthorized = verifyAuth(authCriteria, props);
  return (
    isAuthorized ? (
      <Component {...props} />
    ) : (
      <Redirect 
        to={{ 
          pathname: redirectPath, 
          state: { from: props.location },
        }} 
      />
    )
  );
};

// TODO: authenticate user
const validUser = _props => true; 
// The next route must have been referred by a previous route
const internalReferral = props => defined(props.location.state);

// The Store route has different authentication requirements
// than the other two routes 
const storeCriteria = [validUser];
const mainCriteria = [validUser, internalReferral];

const authRoute = withAuth({ authCriteria: mainCriteria });

const ProtectedRoutes = {
  Store: withAuth({ authCriteria: storeCriteria })(Store),
  Shipping: authRoute(Shipping),
  Checkout: authRoute(Checkout),
};

const AppRouter = () => {
  return (
    <Router>
      <Switch>
        <Route exact path='/' component={ProtectedRoutes.Store} />
        <Route exact path='/shipping' component={ProtectedRoutes.Shipping} />
        <Route exact path='/checkout' component={ProtectedRoutes.Checkout} />
        <Route render={() => (<h2>Not Found</h2>)} />
      </Switch>
    </Router>
  );
};


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...