Обработка защищенных/частных маршрутов с использованием React Router v6

Обработка защищенных/частных маршрутов в приложении React является распространенным требованием. Во многих случаях мы хотим ограничить доступ к определенным маршрутам и разрешить их просмотр только аутентифицированным пользователям. В этой статье мы рассмотрим, как обрабатывать частные маршруты с помощью react-router v6.

Мы начнем с создания приложения React; вы можете использовать npm или пряжу.

npx create-reacte-app protected-routes
npm install react-router-dom

or

yarn create react-app protected-routes
yarn add react-router-dom

Далее мы создадим базовое приложение с незащищенными роутерами,

import logo from './logo.svg';
import './App.css';
import { Routes, Route, Link } from 'react-router-dom';
import Home from './pages/home';
import Cart from './pages/cart';
import Profile from './pages/profile';
import Login from './pages/login';
import { useState } from 'react';

function App() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [authenticated, setAuthenticated] = useState(false);

  return (
    <div className='App'>
      <nav className='nav'>
        <Link to={'/'}>Home</Link>
        <Link to={'/cart'}>Cart</Link>
        <Link to={'/profile'}>Profile</Link>
        <Link to={'/login'}>Login</Link>
      </nav>
      <Routes>
        <Route
          path='/'
          element={<Home />}
        />
        <Route
          path='/cart'
          element={<Cart />}
        />
        <Route
          path='/profile'
          element={<Profile />}
        />
        <Route
          path='/login'
          element={
            <Login
              username={username}
              setUsername={setUsername}
              password={password}
              setPassword={setPassword}
              loginFun={() => setAuthenticated(true)}
            />
          }
        />
      </Routes>
    </div>
  );
}

export default App;

Здесь я создал простое приложение, которое имеет 4 маршрута; домашняя страница, корзина, профиль и вход. Эти страницы представляют собой не что иное, как простой компонент, возвращающий заголовок, показывающий, что это за страницы.

import React from "react";

const Home = () => {
    return (
        <div>
            <h1>This is Home Page</h1>
        </div>
    )
}

export default Home;

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

Теперь мы начнем с нашего традиционного подхода к созданию защищенных маршрутов. Мы создадим компонент, в который мы перейдем, если пользователь аутентифицирован, и он соответственно вернет нам маршрут.

// privateRoute.jsx

import React from 'react';
import { Route } from 'react-router-dom';

const PrivateRoute = ({ auth, path, element }) => {
  return auth ? (
    <Route
      path={path}
      element={element}
    />
  ) : null;
};

export default PrivateRoute;
// App.jsx

<Route
   path='/'
   element={<Home />}
 />
<PrivateRoute
  auth={authenticated}
  path={'/cart'}
  element={<Cart />}
/>
<Route
  path='/profile'
  element={<Profile />}
/>

Но при этом вы получите ошибку. Эта ошибка возникает из-за того, что в версии 6 react-router-dom все компоненты, которые являются дочерними элементами компонента «Routes», должны быть «Route». Следовательно, нам не будет позволено размещать любой пользовательский частный маршрут напрямую, даже если он просто возвращает компонент «Маршрут».

Поэтому мы должны найти другой способ реализации частных маршрутов. Здесь в игру вступает ‹Outlet/›. Согласно официальным документам -

«В родительских элементах маршрута следует использовать <Outlet> для отображения их дочерних элементов маршрута. Это позволяет отображать вложенный пользовательский интерфейс при отображении дочерних маршрутов. Если родительский маршрут точно соответствует, будет отображаться дочерний индексный маршрут или ничего, если индексного маршрута нет».

Проще говоря, Outlet позволяет нам эффективно создавать сложный вложенный пользовательский интерфейс, то есть вместо написания сложных шаблонов маршрутов, таких как

<Route path="/dashboad/messages/:id" element={...}/>

Вы можете легко вложить их

<Route path="/dashboard" element={...}>
  <Route path="messages" element={...}>
    <Route path=":id" element={...}/>
  </Route>
</Route>

Вложив маршруты таким образом, вы можете отобразить 3 разных компонента, т. е. «/dashboard» отобразит компонент Dashboard, а когда пользователь перейдет к «/dashboard/message», снова отобразится другой компонент сообщений, если пользователь перейдет к «/dashboard/messages». /:id», то может быть отображен другой компонент.

Вы также можете посетить фрагмент кода, предоставленный официальной документацией react-router-dom здесь.

Итак, поняв, что мы вернемся к нашей основной теме частных маршрутов.

Здесь мы устраним нашу ошибку с помощью ‹Outlet›.

// App.jsx
.....
.....
<Routes>
  {/* Here we have nested our routes inside another route */}
  <Route
    path='/'
    element={<Authenticated auth={authenticated} />}
    >
      <Route
         path='/'
         element={<Home />}
       />
       <Route
         path='/cart'
         element={<Cart />}
       />
       <Route
         path='/profile'
         element={<Profile />}
        />
    </Route>
        ....
</Routes>
.....
.....
// authenticate.jsx

import React from 'react';
import { Navigate, Outlet } from 'react-router-dom';

const Authenticated = ({ auth }) => {
  return auth ? <Outlet /> : <Navigate to={'/login'} />;
};

export default Authenticated;

Этот аутентифицированный компонент проверяет, аутентифицирован ли пользователь с помощью реквизита аутентификации, и отображает компонент ‹Outlet/›; если он аутентифицирован, он соответствует пути и отображает запрошенный компонент, а если пользователь не аутентифицирован, пользователь перенаправляется на страницу входа с помощью компонента ‹Navigate/›, который является заменой старого компонента ‹Redirect/›.

Заключение

В этой статье мы рассмотрели, как обрабатывать частные маршруты с помощью react-router v6. Мы узнали, что react-router-dom v6 не позволяет компоненту Routes иметь дочерние элементы, отличные от Route. Поэтому мы ввели ‹Outlet/› для решения проблемы частных маршрутов, а также создали компонент Authenticated для ограничения доступа к определенным маршрутам и использовали его для защиты маршрутов серверов. Мы также узнали, как обрабатывать перенаправления, если пользователь не аутентифицирован. Обладая этими знаниями, вы сможете легко обрабатывать частные маршруты в своих приложениях React.

Если вы хотите узнать больше о концепциях кодирования в деталях, обязательно ознакомьтесь с нашим Курсом веб-разработки Full Stack. Удачного кодирования!