Необнаруженная ошибка: не удалось найти соответствующий маршрут при перенаправлении на страницу /login после выхода из системы

Я пытаюсь реализовать JWT в своем проекте, и статья предлагает хорошее решение:

https://dev.to/sanjayttg/jwt-authentication-in-react-with-react-router-1d03.

Маршруты.jsx

import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { useAuth } from "../provider/authProvider";
import { ProtectedRoute } from "./ProtectedRoute";
import Login from "../pages/Login";
import Logout from "../pages/Logout";

const Routes = () => {
  const { token } = useAuth();

  // Define public routes accessible to all users
  const routesForPublic = [
    {
      path: "/service",
      element: <div>Service Page</div>,
    },
    {
      path: "/about-us",
      element: <div>About Us</div>,
    },
  ];

  // Define routes accessible only to authenticated users
  const routesForAuthenticatedOnly = [
    {
      path: "/",
      element: <ProtectedRoute />, // Wrap the component in ProtectedRoute
      children: [
        {
          path: "",
          element: <div>User Home Page</div>,
        },
        {
          path: "/profile",
          element: <div>User Profile</div>,
        },
        {
          path: "/logout",
          element: <Logout/>,
        },
      ],
    },
  ];

  // Define routes accessible only to non-authenticated users
  const routesForNotAuthenticatedOnly = [
    {
      path: "/",
      element: <div>Home Page</div>,
    },
    {
      path: "/login",
      element: <Login/>,
    },
  ];

  // Combine and conditionally include routes based on authentication status
  const router = createBrowserRouter([
    ...routesForPublic,
    ...(!token ? routesForNotAuthenticatedOnly : []),
    ...routesForAuthenticatedOnly,
  ]);

  // Provide the router configuration using RouterProvider
  return <RouterProvider router = {router} />;
};

export default Routes;

ProtectedRoute.jsx

import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "../provider/authProvider";

export const ProtectedRoute = () => {
  const { token } = useAuth();

  // Check if the user is authenticated
  if (!token) {
    // If not authenticated, redirect to the login page
    return <Navigate to = "/login" />;
  }

  // If authenticated, render the child routes
  return <Outlet />;
};

Гитхаб: https://github.com/sanjay-arya/react-auth-demo

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

Предоставленный код работает нормально и так. Проблема возникает, когда я хочу перенаправить пользователя на страницу "/login" вместо страницы "/" после выхода из системы. например Я изменил navigate("/", { replace: true }) на navigate("/login", { replace: true }); в Logout.jsx.

Я получаю эту ошибку:

react-router-dom.js?v=7652cf65:202 Uncaught Error: Could not find a matching route for errors on route IDs: 2
    at invariant (react-router-dom.js?v=7652cf65:202:11)
    at _renderMatches (react-router-dom.js?v=7652cf65:3167:33)
    at useRoutesImpl (react-router-dom.js?v=7652cf65:3033:25)
    at DataRoutes (react-router-dom.js?v=7652cf65:3422:10)
    at renderWithHooks (react-dom_client.js?v=7652cf65:12171:26)
    at updateFunctionComponent (react-dom_client.js?v=7652cf65:14577:28)
    at beginWork (react-dom_client.js?v=7652cf65:15912:22)
    at HTMLUnknownElement.callCallback2 (react-dom_client.js?v=7652cf65:3674:22)
    at Object.invokeGuardedCallbackDev (react-dom_client.js?v=7652cf65:3699:24)
    at invokeGuardedCallback (react-dom_client.js?v=7652cf65:3733:39)
Show 19 more frames
console.js:213 The above error occurred in the <DataRoutes> component:

    at DataRoutes (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3419:5)
    at Router (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3491:15)
    at RouterProvider (http://localhost:5173/node_modules/.vite/deps/react-router-dom.js?v=7652cf65:3375:5)
    at Routes (http://localhost:5173/src/routes/index.jsx?t=1712483351401:26:7)
    at AuthProvider (http://localhost:5173/src/provider/authProvider.jsx:21:3)
    at App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.

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

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
0
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Обновите Routes, чтобы удалить проверку token и безоговорочно визуализировать routesForNotAuthenticatedOnly маршруты, а также создайте «компонент защищенного маршрута», который выполняет обратную функцию ProtectedRoute, чтобы защитить эти маршруты от аутентифицированных пользователей.

Поскольку на корневом маршруте "/" есть «защищенная» домашняя страница пользователя и «анонимная» домашняя страница, создайте специальный компонент, который проверяет условие аутентификации и условно отображает любую из домашних страниц в общедоступных маршрутах, доступных любому. в любое время.

Пример:

import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "../provider/authProvider";

export const AnonymousRoute = () => {
  const { token } = useAuth();

  // Check if the user is authenticated
  if (!token) {
    // If not authenticated, render the child routes
    return <Outlet />;
  }

  // If authenticated, redirect to safe page
  return <Navigate to = "/" />;
};
import { RouterProvider, createBrowserRouter } from "react-router-dom";
import { useAuth } from "../provider/authProvider";
import { ProtectedRoute } from "./ProtectedRoute";
import { AnonymousRoute } from "./ProtectedRoute";
import Login from "../pages/Login";
import Logout from "../pages/Logout";

const HomePage = () => {
  const { token } = useAuth();

  return token
    ? <div>User Home Page</div>
    : <div>Home Page</div>;
};

const Routes = () => {
  // Define public routes accessible to all users
  const routesForPublic = [
    {
      path: "/",
      element: <HomePage />,
    },  
    {
      path: "/service",
      element: <div>Service Page</div>,
    },
    {
      path: "/about-us",
      element: <div>About Us</div>,
    },
  ];

  // Define routes accessible only to authenticated users
  const routesForAuthenticatedOnly = [
    {
      element: <ProtectedRoute />,
      children: [
        {
          path: "/profile",
          element: <div>User Profile</div>,
        },
        {
          path: "/logout",
          element: <Logout />,
        },
      ],
    },
  ];

  // Define routes accessible only to non-authenticated users
  const routesForNotAuthenticatedOnly = [
    {
      element: <AnonymousRoute />,
      children: [
        {
          path: "/login",
          element: <Login />,
        },
      ],
    },
  ];

  // Combine and conditionally include routes based on authentication status
  const router = createBrowserRouter([
    ...routesForPublic,
    ...routesForNotAuthenticatedOnly),
    ...routesForAuthenticatedOnly,
  ]);

  // Provide the router configuration using RouterProvider
  return <RouterProvider router = {router} />;
};

export default Routes;

Спасибо! Но когда вы говорите: «Некоторые маршруты, по которым вы хотите перейти, еще не смонтированы и не отображены», я изначально думал, что для const handleLogout = () => { setToken(); navigate("/", { replace: true }); }; setToken() сначала переотобразит компонент <Routes> и смонтирует правильный маршрутизатор, т. е. тот, который включает routesForNotAuthenticatedOnly перед навигация. Почему обновленный маршрутизатор еще не отрендерен и не смонтирован?

byles1506 07.04.2024 20:31

@ byles1506 Это связано с тем, что обновления состояния React обрабатываются асинхронно, а действия навигации выполняются немедленно. Думайте о любой из функций React setState как о «React при ближайшем удобном случае, пожалуйста, обновите это состояние до этого значения», и React помещает обновление в очередь для обработки между циклами рендеринга. Надеюсь, эта аналогия имеет смысл.

Drew Reese 07.04.2024 20:38

@ byles1506 Альтернативой является размещение вызова navigate в setTimeout, чтобы он помещался в конец очереди событий Javascript и вызывался после обработки всех поставленных в очередь обновлений состояния React. Однако это своего рода хитрость, и ее не рекомендуется использовать, если вам подходят обычные средства, предложенные в ответе.

Drew Reese 07.04.2024 20:40

Другие вопросы по теме