明明还没搞懂v5v6就出了,学不动了哇。
这里总结下v6版本的简要使用。

[v5版本链接]()

v6版本

官网链接

开始

这里我们已经创建了一个空的React项目

安装

yarn add react-router-dom

BrowserRouter

这里我们选择BrowserRouter模式

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

Link

进入App.jsx我们添加一些链接

/*
 * @Date: 2022-02-15 19:01:38
 * @LastEditors: zhangheng
 * @LastEditTime: 2022-02-15 19:18:48
 */
import React, { memo } from "react";
import { Link } from "react-router-dom";

export default memo(function index() {

  return (
    <div>
      <h1>hello react router</h1>
      <Link to="/router1">router1</Link> | <Link to="/router2">router2</Link>
    </div>
  );
});

此时应用展示如下:
image-20220215192304599

当我们点击链接后url就会改变,当然页面不会有任何的变化。

image-20220215193040629

渲染路由组件

我们创建两个组件:
image-20220215194829039

main.tsx文件中引入,再使用RouteRoutes

这里注意我们在v5是使用Switch组件包裹路由组件,v6则是移除了Switch,转而使用Routes了。

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}></Route>
        <Route path="/router1" element={<Router1 />}></Route>
        <Route path="/router2" element={<Router2 />}></Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

嵌套路由

上述的案例我们点击后就只会显示对应组件的信息,破坏了布局,这时我们想在App中展示路由组件可以按照如下修改:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
            <Route path="/router1" element={<Router1 />}></Route>
            <Route path="/router2" element={<Router2 />}></Route>
        </Route>
    
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

当然我们需要在App组件中去渲染要展示的组件:
使用Outlet组件

/*
 * @Date: 2022-02-15 19:01:38
 * @LastEditors: zhangheng
 * @LastEditTime: 2022-02-15 20:08:42
 */
import React, { memo } from "react";
import { Link, Outlet } from "react-router-dom";

export default memo(function index() {
  //props/state

  //redux hooks

  //other hooks

  //其他逻辑

  return (
    <div>
      <h1>hello react router</h1>
      <Link to="/router1">router1</Link> | <Link to="/router2">router2</Link>
      <Outlet />
    </div>
  );
});

此时点击我们发现组件就先是在父组件中了,共用了父组件的布局。
image-20220215200921579

动态路由匹配

我们修改一个链接:

/*
 * @Date: 2022-02-15 19:01:38
 * @LastEditors: zhangheng
 * @LastEditTime: 2022-02-15 20:08:42
 */
import React, { memo } from "react";
import { Link, Outlet } from "react-router-dom";

export default memo(function index() {
  //props/state

  //redux hooks

  //other hooks

  //其他逻辑

  return (
    <div>
      <h1>hello react router</h1>
      <Link to="/router1">router1</Link> | <Link to="/router2/123">router2</Link>
      <Outlet />
    </div>
  );
});

此时我们点击router2链接,页面会跳转到空白,同时控制台会报出警告不匹配/router2/123

我们可以添加一个匹配项:

*是在匹配不到其他的组件的时候就被匹配,当然这样就消除了警告,跳转到404页面了。

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route path="router1" element={<Router1 />}></Route>
          <Route path="router2" element={<Router2 />}></Route>
          <Route path="*" element={<h2>404</h2>}></Route>
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

但是我们只是想通过这个方式去传递某一个参数,比如,实际项目中/router2/123中的123可能是变量,对应router2中的页面只是去获得这个变量来请求获取不同的数据。所以我们要在组件匹配的path作出修改:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
import Router2s from "./pages/router2s";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route path="router1" element={<Router1 />}></Route>
          <Route path="router2" element={<Router2s />}>
            <Route path=":numberId" element={<Router2 />}></Route>
          </Route>
          <Route path="*" element={<h2>404</h2>}></Route>
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

此时点击router2/123就会正确跳转到router2页面了,我们再获取这个numberId

/*
 * @Date: 2022-02-15 19:43:21
 * @LastEditors: zhangheng
 * @LastEditTime: 2022-02-15 20:21:57
 */
import React, { memo } from "react";
import { useParams } from "react-router-dom";

export default memo(function index() {
  //props/state

  //redux hooks

  //other hooks
  const params = useParams();
  console.log(params);
  //其他逻辑

  return <div>这是router2组件</div>;
});

结果如下:
image-20220215203829154

索引路由

我们接着上述的案例,当我们的url/router2/123时,会正常显示router2的组件,但是我们手动将url改为router2/此时就不会显示numberId,我们可以使用Index Routes来解决这个问题:

import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import App from "./App";
import Router1 from "./pages/router1";
import Router2 from "./pages/router2";
import Router2s from "./pages/router2s";

ReactDOM.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<App />}>
          <Route path="router1" element={<Router1 />}></Route>
          <Route path="router2" element={<Router2s />}>
            <Route index element={<span>没有</span>} />
            <Route path=":numberId" element={<Router2 />} />
          </Route>

          <Route path="*" element={<h2>404</h2>}></Route>
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>,
  document.getElementById("root")
);

当我们跳转到/router2后满足匹配父组件,但是没有匹配任何一个子组件就匹配index,这种情况适用于用户还没有点击导航列表中的一个项目时,默认展示的一个组件。

v6新的变化解读

上述简单展示了v6如何使用路由,这里我们讲解下其中的不同之处。

Routes

新的版本移除了Switch,是因为以往的路由匹配方式依赖于你书写的路由渲染位置,而v6要聪明的多。

这是一个官网的案例:

<Routes>
    <Route path="teams/:teamId" element={<Team />} />
    <Route path="teams/new" element={<NewTeamForm />} />
</Routes>

我们输入路径teams/new就会匹配到teams/new了,毕竟这个路径更具体。

OutLet

用于在父组件中渲染匹配到的子组件

useRoutes

这个方法可以替代以往使用的react-router-config这个库了,将路由的配置单独放置在一个文件中,实现类似vue配置路由的方式。

import React, { memo, useEffect } from 'react';
import { useRoutes } from 'react-router-dom';
//导入路由配置文件
import routes from './router';
function App() {
  //这个钩子要写在路由组件中
  const element = useRoutes(routes);
  return (
      <div className="App overflow-auto">{element}</div>
  );
}

export default memo(App);

路由文件:

/*
 * @Date: 2022-01-23 20:15:56
 * @LastEditors: zhangheng
 * @LastEditTime: 2022-01-31 19:12:10
 */
import React, { lazy, Suspense } from 'react';
import type { RouteObject } from 'react-router-dom';

const routes: RouteObject[] = [
  {
    path: '/*',
    element: () => import('@/pages/main'),
    children: [
      { path: '', element: () => import('@/pages/home') },
      {
        path: 'article/:articleId',
        element: () => import('@/pages/article')
      }
    ]
  },
  {
    path: '/signup',
    element: () => import('@/pages/signUp')
  }
];

type lazyPropsType = () => Promise<{ default: React.ComponentType }>;
interface propsType {
  importRoute: lazyPropsType;
}

//定义自动包裹Suspense函数
function LazyElement(props: propsType) {
  const { importRoute } = props;
  const LazyComponent = lazy(importRoute);
  return (
    <Suspense fallback={<div>路由懒加载...</div>}>
      <LazyComponent />
    </Suspense>
  );
}

// 处理routes 如果element是懒加载,要包裹Suspense
function dealRoutes(routesArr: RouteObject[]) {
  if (routesArr && Array.isArray(routesArr) && routesArr.length > 0) {
    routesArr.forEach((route) => {
      if (route.element && typeof route.element == 'function') {
        const importRoute = route.element as lazyPropsType;
        route.element = <LazyElement importRoute={importRoute} />;
      }
      if (route.children) {
        dealRoutes(route.children);
      }
    });
  }
}
dealRoutes(routes);

export default routes;

以上就是我目前使用到的v6版本特性,更多的在我使用后再总结补充。

Last modification:March 7, 2022
如果觉得我的文章对你有用,请随意赞赏