环境配置:vite+ts+react18
1、安装包
2、 根路由配置以及路由挂载
a、在src下面创建router文件夹配置简单的路由信息:
router/index.tsx
import { createBrowserRouter } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import HomePage from "@/views/home/homePage";
import React from "react";
const router = createBrowserRouter([
  {
    path: "/login",//地址
    name: "login",//路由名
    // element: React.createElement(UserLogin),
    element: <UserLogin />,//要跳转的组件
  },
  {
    path: "/",
    name: "home",
    element: <HomePage />,
  },
]);
export default router;
b、在实际开发中,一半选择app组件作为路由挂载导出:
app.tsx
import React from "react";
import { RouterProvider } from "react-router-dom";
import router from "./router";
const App: React.FC = () => {
  return <RouterProvider router={router} />;
};
export default App;
c、在main挂载app
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "antd/dist/reset.css";
import store from "./store";
import { Provider } from "react-redux";
ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>,
);
这样路由就可以使用了。不过现在只是通过手动访问可以了。
3、路由跳转
3.1、useNavigate(高)
 
- 用途:用于程序化导航,允许你在组件内部触发跳转。
- 示例
import { useNavigate } from 'react-router-dom';
function MyComponent() {
  const navigate = useNavigate();
  function handleClick() {
    navigate('/some/path');
  }
  return (
    <button onClick={handleClick}>
      Go to '/some/path'
    </button>
  );
}3.2、useLocation(高)
 
- 用途:获取当前路由的位置信息。
- 示例:
-  import { useLocation } from 'react-router-dom'; function MyComponent() { const location = useLocation(); return ( <div> <h1>You are at: {location.pathname}</h1> </div> ); }3.3、useParams(高)
- 用途:从当前 URL 中获取动态参数。常用于动态路由
- 示例:
import { useParams } from 'react-router-dom';
function UserPage() {
  const params = useParams();
  return (
    <div>
      <h1>User ID: {params.userId}</h1>
    </div>
  );
}3.4、useResolvedPath
 
- 用途:解析一个路径到一个完整的路径对象。
- 示例
import { useResolvedPath } from 'react-router-dom';
function Link({ to }) {
  let resolved = useResolvedPath(to);
  let href = resolved.pathname + resolved.search;
  return <a href={href}>{to}</a>;
}3.5、useMatch:
 
- 用途:检查一个路径是否与当前 URL 匹配。
- 示例
import { useMatch } from 'react-router-dom';
function MyComponent() {
  const match = useMatch('/users/:userId');
  if (match) {
    return <div>User ID: {match.params.userId}</div>;
  }
  return null;
}3.6、useOutlet
 
- 用途:渲染嵌套路由的子路由内容。
- 示例:
import { useOutlet } from 'react-router-dom';
function OutletComponent() {
  const outlet = useOutlet();
  return (
    <div>
      {outlet}
    </div>
  );
}4、路由详细配置
4.1、配置详情
在 react-router-dom 中,路由配置通常包含以下几个关键的部分:
-  path:- 用途:定义路由的路径模式。
- 示例:
- 解释:这里的 path定义了一个路径模式,其中:userId是一个动态参数。
 
-  element:- 用途:定义当路由匹配时应该渲染的 React 组件。
- 示例:
- 解释:当路径匹配时,<UserProfile />组件将会被渲染。
 
-  index(可选):- 用途:表示这是一个索引路由,当没有具体路径匹配时渲染。
- 示例:
- 解释:当路径为空或者没有具体的匹配时,<Home />组件将会被渲染。
 
-  children(可选):- 用途:定义嵌套路由。
- 示例:
- 解释:这里的 children定义了一个子路由,当父路由匹配时,子路由也会被考虑。
 
-  loader(可选):- 用途:加载数据的函数,常用于数据预取。
- 示例:
- 解释:这个函数会在路由激活前执行,通常用来获取数据。
 
-  errorElement(可选):- 用途:定义当路由发生错误时渲染的组件。
- 示例:
- 解释:当路由加载过程中出现错误时,<Error />组件会被渲染。
 
-  caseSensitive(可选):- 用途:定义路径匹配是否区分大小写。
- 示例:
- 解释:默认情况下路径匹配是不区分大小写的,但可以通过此选项改变这一行为。
 
4.2、例子
typescript
import { createBrowserRouter, RouterProvider, Route } from "react-router-dom";
import RootLayout from "./layouts/RootLayout";
import Home from "./pages/Home";
import About from "./pages/About";
import Users from "./pages/Users";
import UserProfile from "./pages/UserProfile";
// 定义路由对象
const router = createBrowserRouter([
  {
    path: "/",
    element: <RootLayout />,
    children: [
      {
        index: true,
        element: <Home />,
      },
      {
        path: "about",
        element: <About />,
      },
      {
        path: "users",
        element: <Users />,
        children: [
          {
            path: ":userId",
            element: <UserProfile />,
          },
        ],
      },
    ],
  },
]);
// 在 App 组件中使用 RouterProvider 提供路由配置
function App() {
  return (
    <RouterProvider router={router} />
  );
}
export default App;5、路由重定向
5.1、条件重定向
比如用户是否已登录。这种情况下,你可以在路由组件中使用条件逻辑来决定是否重定向。
import { Navigate, createBrowserRouter } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import HomePage from "@/views/home/homePage";
import React from "react";
import { getToken } from "../utils/storeages";
const isLogin = getToken("token");
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    // element: React.createElement(UserLogin),
    element: <UserLogin />,
  },
  {
    path: "/",
    name: "home",
    element: isLogin ?  <HomePage /> : <Navigate to="/login"  replace />,//条件判断
  },
]);
export default router;
5.2、直接重定向--redirect
推荐使用这一个,方便用于登录认证
import { Navigate, createBrowserRouter, redirect } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import ModelPage from "@/views/model";
import HomePage from "@/views/home/homePage";
import DashboardPage from "@/views/Dashboard/DashboardPage";
import React from "react";
import { getToken } from "../utils/storeages";
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    element: <UserLogin />,
    loader: () => {
      console.log(getToken("token"));
      if (getToken("token")) {
        console.log(1111);
        return redirect("/home");
      } else {
        console.log(2222);
        return redirect("/login");
      }
    },
  },
  {
    path: "/",
    name: "model",
    element: <ModelPage />,
    children: [
      {
        path: "/home",
        name: "home",
        element: <HomePage />,
      },
      {
        path: "/dashboard",
        name: "dashboard",
        element: <DashboardPage />,
      },
      {
        path: "*",
        element: <Navigate to="/home" />,
      },
    ],
  },
]);
export default router;
6、动态路由
动态路由其实很简单,简单来说就是一个组件展示不同的数,类似于查看用户信息。每个用户信息不一样,但是组件只有一个。
配置动态路由:
 router.tsx
import { Navigate, createBrowserRouter } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import HomePage from "@/views/home/homePage";
import React from "react";
import { getToken } from "../utils/storeages";
const isLogin = getToken("token");
console.log(isLogin);
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    // element: React.createElement(UserLogin),
    element: <UserLogin />,
  },
  {
    path: "/home/:userId",//动态参数
    name: "home",
    // element: isLogin ?  <HomePage /> : <Navigate to="/login"  replace />,
    element:<HomePage />,
  },
]);
export default router;
跳转的起点:
import React from "react";
import { useNavigate } from "react-router-dom";
const UserLogin: React.FC = () => {
  const navigate = useNavigate();
  function handleClick() {
    navigate("/home/1");
  }
  return (
    <div >
      <button onClick={handleClick}>Go to User 1</button>
    </div>
  );
};
export default UserLogin;
跳转的目标:
import React from "react";
import { useParams } from "react-router-dom";
const HomePage: React.FC = () => {
  const {userId} = useParams()
  console.log(userId);
  return <div>homePage{userId}</div>;
};
export default HomePage;
7、嵌套路由(子路由)
配置嵌套路由:
import { Navigate, createBrowserRouter } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import HomePage from "@/views/home/homePage";
import HaderPage from '@/views/home/header/header'
import React from "react";
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    element: <UserLogin />,
  },
  {
    path: "/home",
    name: "home",
    element:<HomePage />,
    children: [
      {
        path: "/home/header",
        name: "header",
        element: <HaderPage />,
      },
    ],
  },
]);
export default router;
配置home组件:
import React from "react";
import { useParams,useNavigate,Outlet } from "react-router-dom";
const HomePage: React.FC = () => {
  const {userId} = useParams()
  const navigate = useNavigate()
  console.log(userId);
  const headerButon = () => {
    console.log(111);
    navigate("/home/header")
  };
  return (
    <div>
          <div>homePage{userId}</div>
    <button onClick={() => {headerButon()}}>展示header</button>
    <Outlet/>
    </div>
  );
};
export default HomePage;
展示的子组件:
import React from "react";
const HeaderPage: React.FC = () => {
  return <div>HeaderPage</div>;
};
export default HeaderPage;8、默认路由
在实际开发中在未操作的情况下会默认展示一个页面,这个页面我们成为默认路由页面
import { Navigate, createBrowserRouter } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import ModelPage from "@/views/model";
import HomePage from "@/views/home/homePage";
import DashboardPage  from "@/views/Dashboard/DashboardPage";
import React from "react";
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    element: <UserLogin />,
  },
  {
    path: "/",
    name: "model",
    element: <ModelPage />,
    children: [
      {
        path: "/home",
        name: "home",
        element: <HomePage />,
      },
      {
        path: "/dashboard",
        name: "dashboard",
        element: <DashboardPage />,
      },
      {
        path: "*",//默认路由指向的页面
        element: <Navigate to="/home" />,
      },
    ],
  },
]);
export default router;
9、路由守卫
方法 1: 使用 useEffect 和 useHistory / useNavigate
 
这里其实没什么变化,主要是加了一个loader下面的redirect重定向路由
router.tsx
import { Navigate, createBrowserRouter,redirect } from "react-router-dom";
import UserLogin from "@/views/login/loginPage";
import HomePage from "@/views/home/homePage";
import DashboardPage  from "@/views/dashboard/dashboardPage";
import React from "react";
import { LayoutGuard } from "./utils/guard";
import { getToken } from "@/utils/storeages";
const router = createBrowserRouter([
  {
    path: "/login",
    name: "login",
    element: <UserLogin />,
    loader: () => {
      const token = getToken('token');
      if (token) {
        return redirect('/home');
      }
      return null;
    },
  },
  {
    path: "/",
    name: "model",
    // element: <ModelPage />,
    element: <LayoutGuard />,
    children: [
      {
        path: "/home",
        name: "home",
        element: <HomePage />,
      },
      {
        path: "/dashboard",
        name: "dashboard",
        element: <DashboardPage />,
      },
      {
        path: "*",
        element: <Navigate to="/home" />,
      },
    ],
  },
]);
export default router;
router/authGuard.tsx
守卫操作:
import React, { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { getToken } from '@/utils/storeages';
function AuthGuard({ children }: { children: JSX.Element }) {
  const navigate = useNavigate();
  useEffect(() => {
    const token = getToken('token');
    console.log('token', token);
    if (token) {
      // 如果已经登录,则重定向到登录页面
      navigate('/home');
    } else {
       navigate('/login');
    }
  }, [navigate]);
  return <>{children}</>;
}
export default AuthGuard;封装路由组件中导入的 <LayoutGuard />,
import AuthGuard from "./AuthGuard";
import ModelPage from "@/views/model";
import React from "react";
export const LayoutGuard = () => {
  return (
    <AuthGuard>
      <ModelPage />
    </AuthGuard>
  );
};
方法 2: 使用自定义高阶组件 (HOC)
这种方法可以让你更灵活地控制路由组件的行为,特别是在需要复用相同逻辑的情况下。
import React from 'react';
import { useNavigate } from "react-router-dom";
function withAuth(WrappedComponent) {
  return function AuthenticatedComponent(props) {
    const navigate = useNavigate();
    const isLoggedIn = false; // 假设这是从你的应用状态中获取的值
    if (!isLoggedIn) {
      // 如果用户未登录,则重定向到登录页面
      navigate('/login');
      return null;
    }
    return <WrappedComponent {...props} />;
  };
}
function ProtectedPage() {
  return (
    <div>
      <h1>Welcome to the protected area!</h1>
    </div>
  );
}
const AuthenticatedProtectedPage = withAuth(ProtectedPage);
function App() {
  return (
    <div>
      <AuthenticatedProtectedPage />
    </div>
  );
}
export default App;方法 3: 使用 Route 的 element 属性
 
在 React Router v6 中,你可以直接在 Route 的 element 属性中定义一个组件,该组件负责路由守卫的逻辑。
import React from 'react';
import { createBrowserRouter, RouterProvider, Route, Link, useNavigate } from "react-router-dom";
function ProtectedPage() {
  const isLoggedIn = false; // 假设这是从你的应用状态中获取的值
  const navigate = useNavigate();
  if (!isLoggedIn) {
    // 如果用户未登录,则重定向到登录页面
    navigate('/login');
    return null;
  }
  return (
    <div>
      <h1>Welcome to the protected area!</h1>
    </div>
  );
}
function App() {
  return (
    <div>
      <Route path="/protected" element={<ProtectedPage />} />
    </div>
  );
}
const router = createBrowserRouter([
  {
    path: '/',
    element: <App />,
    children: [
      {
        path: '/protected',
        element: <ProtectedPage />,
      },
    ],
  },
]);
function Root() {
  return (
    <RouterProvider router={router} />
  );
}
export default Root;方法 4: 使用 useLocation 和条件渲染
 
这种方法适用于需要在组件内部根据当前 URL 执行某些逻辑的情况。
import React, { useEffect } from 'react';
import { useNavigate, useLocation } from "react-router-dom";
function ProtectedRoute({ children }) {
  const navigate = useNavigate();
  const location = useLocation();
  const isLoggedIn = false; // 假设这是从你的应用状态中获取的值
  useEffect(() => {
    if (!isLoggedIn && location.pathname === '/protected') {
      // 如果用户未登录并且试图访问受保护的页面,则重定向到登录页面
      navigate('/login');
    }
  }, [isLoggedIn, navigate, location]);
  return isLoggedIn ? children : null;
}
function App() {
  return (
    <div>
      <ProtectedRoute>
        <h1>Welcome to the protected area!</h1>
      </ProtectedRoute>
    </div>
  );
}
export default App;总结
-  使用 useEffect和useHistory/useNavigate:- 适用于简单的场景,可以在组件加载时检查条件并进行重定向。
 
-  使用自定义高阶组件 (HOC): - 更适合需要复用相同逻辑的情况,可以方便地应用于多个组件。
 
-  使用 Route的element属性:- 直接在 Route的element属性中定义一个组件,该组件负责路由守卫的逻辑。
 
- 直接在 
-  使用 useLocation和条件渲染:- 适用于需要根据当前 URL 执行某些逻辑的情况。
 
选择哪种方法取决于你的具体需求和应用场景。










