1. 程式人生 > 其它 >react-router-dom 【V6新變化】

react-router-dom 【V6新變化】

react-router-dom

react-router-dom v6整體體驗相對於v5,體驗要好很多,最大的一個改變,就是曾經的Route不可巢狀,整個路由配置必須拆分成若干小塊,除非通過react-router-config這種外掛,才可以實現對整個路由的管理,然而現在,不需要任何外掛就可以實現對路由配置的管理。

安裝

 npm install --save react-router-dom history

react,react-router-dom以及相關外掛版本

"dependencies": {
  "history": "^5.1.0",
  "react": "^17.0.2",
  "react-dom": "^17.0.2",
  "react-router-dom": "^6.0.2"
}

如果是自己通過webpack配置的專案,一定要在devServe中配置historyApiFallback,以及output.publicPath解決history模式頁面重新整理後出現404情況。

devServer: {
  port,
  host,
  hot: true,
  open: true,
  historyApiFallback:{
    disableDotRule: true
  }
},

// 以及 `output` 中的 publicPath
output: {
  path: path.resolve(__dirname, "../dist"),
  filename: "[name].[chunkhash].js",
  publicPath: '/'
},

使用
在檔案中直接渲染Router.tsx

// idex.tsx
import React from "react";
import ReactDOM from "react-dom";
import Router from "./router/Router";
import "./index";

ReactDOM.render(<Router />, document.getElementById("root"));

【1】Routes元件替換V5的Switch元件

  • Route元件必須使用Routes巢狀
//Router.tsx
import React from 'react';
import {BrowserRouter,Route,Routes} from 'react-router-dom';
import Home from '../home/Home';
import Goods from '../goods/Goods';
import Customer from '../customer/Customer';

export defealt function Router(){
//所有的路由配置均在BrowserRouter內部
	return(
	<BrowserRouter>
	  {/* 使用 Routes 替換曾經的 Switch */}
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='goods' element={<Goods />} />
        <Route path='customer' element={<Customer />} />
      </Routes>
	<BrowserRouter/>
	)
}

【2】跳轉

  • 通過Link元件跳轉
//Customer.tsx
import React from 'react';
import {Link} from "react-router-dom";
export default function Customer(){
return(
	<div>
	<h2>Customer Page</h2>
	<Link to="/goods">to Goods</Link>
	</div>
)
}
  • 通過useNavigate方法跳轉
//Goods.tsx
import React from 'react';
import {useNavigate} from 'react-router-dom';

export default function Goods(){
 const navigate = useNavigate();
 const handleClickToHome = ()=>{
 	navigate("/");
	//history的replace模式
	//navigate('/',{replace:true})
 };
 return (
 	<div>
	<h2>Goods Page</h2>
	<button onClick={handleClickToHome}>to Home</button>
	</div>
 )
}

【3.匹配未定義的路由】

  • v6移除了Redirect元件,改用Navigate元件。
// Router.tsx
import React from "react";
import { BrowserRouter, Route, Routes, Navigate } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";

export default function Router() {
  {/* 所有的路由配置均在 BrowserRouter 內部 */ }
  return (
    <BrowserRouter>

      {/* 使用 Routes 替換曾經的 Switch */}
      <Routes>
        <Route path='/' element={<Home />} />
        <Route path='goods' element={<Goods />} />
        <Route path='customer' element={<Customer />} />

        {/* 重定向到首頁 */}
        <Route path="*" element={<Navigate to="/"/>} />

        {/* 或者跳轉到 NotFound */}
        {/* <Route path="*" element={<NotFound />} /> */}
      </Routes>
    </BrowserRouter>
  );
}

【4】巢狀路由與動態路由

  • 巢狀路由的path可以不用寫父級,會直接拼寫;
  • 動態路由通過:style的形式實現;
  • 由於/goods/list的匹配度大於/goods/*,所以輸入精確地址會精確匹配,而不是匹配到動態路由;
  • 巢狀路由必須在父級追加 Outlet 元件,作為子級元件的佔位符,類似於vue-router中的router-view。
// Router.tsx
import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";

export default function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Home />}>
          <Route path='goods' element={<Goods />} >
            {/* 動態路由 */}
            <Route path=":id" element={<GoodsDetail />}/>
            <Route path="list" element={<GoodsList />}/>
          </Route>

          <Route path='customer' element={<Customer />} ></Route>
        </Route>

        <Route path="*" element={<NotFound />} /> 
      </Routes>
    </BrowserRouter>
  );
}
// Home.tsx
import React from "react";
import { Outlet, Link } from "react-router-dom";


export default function Home() {

  return (
    <div>
      <h1>Home</h1>
      <p>
        <Link to='/goods'>to goods</Link>
      </p>

      <p>
        <Link to='/customer'>to customer</Link>
      </p>

      <Outlet />
    </div>
  );
}

// Goods.tsx
import React from "react";
import { useNavigate, Outlet } from "react-router-dom";


export default function Goods() {
  const navigate = useNavigate();

  const handleClickToHome = () => {
    navigate("/");

    // history 的 replace 模式
    // navigate("/", { replace: true });
  };
  
  return (
    <div>
      <h2>Goods Page</h2>

      <button onClick={handleClickToHome}>to Home</button>

      {/* 子路由的佔位元件 */}
      <Outlet />
    </div>
  );
}

【5】獲取路由的引數

  • useParams獲取動態路由的值;
  • useSearchParams獲取查詢字串的值。
// GoodsDetail.tsx
import React,{ useEffect } from "react";
import { useParams, useSearchParams  } from "react-router-dom";

export default function GoodsDetail() {
  // 獲取動態路由的值
  const params = useParams();

  // 獲取查詢字串的值
  const [searchParams, setSearchParams] = useSearchParams();
  

  useEffect(() => {
    // 一個物件,key 為動態字串的 key
    console.log(params); // {id: '123'}

    // 一個物件,但是不可直接點出屬性
    console.log(typeof searchParams); // object

    // 輸入 http://localhost:3304/goods/123?name=nihao
    console.log(searchParams.get("name")); // nihao
  }, []);

  const handleAddParams = () => {
    // 修改 查詢字串 的資料
    setSearchParams({
      name:"xxx"
    });
  };
  
  return (
    <div>
      <h2 onClick={handleAddParams}>GoodsDetail Page</h2>
    </div>
  );
}

【6】預設路由

  • 當頁面又多個子路由,比如在/goods時,頁面展示商品列表;/goods/:id時,展示某個商品的詳情。

  • Route的Index屬性就是用來展示預設子路由的。

import React from "react";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";

export default function Router() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path='/' element={<Home />}>
          <Route path='goods' element={<Goods />} >
            {/* 預設 子路由 ,在頁面 路由為 /goods ,會展示該子路由 */}
            <Route index element={<GoodsList />}/>

            <Route path=":id" element={<GoodsDetail />}/>
          </Route>

          <Route path='customer' element={<Customer />} ></Route>
          <Route path="*" element={<NotFound />} /> 
        </Route>

      </Routes>
    </BrowserRouter>
  );
}

【7】通過配置實現路由管理

  • useRoutes可以講陣列物件形式的路由,直接在頁面上使用。
// 入口檔案,src/index.tsx
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index";


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

// src/router/routes.tsx
import React from "react";
import { RouteObject } from "react-router-dom";
import Home from "../home/Home";
import Goods from "../goods/Goods";
import Customer from "../customer/Customer";
import NotFound from "../not-found/NotFound";
import GoodsDetail from "../goods/goods-detail/GoodsDetail";
import GoodsList from "../goods/goods-list/GoodsList";

const routes: RouteObject[] = [
  {
    path: "/",
    element: <Home />,
    children: [
      {
        path: "/goods",
        element: <Goods />,
        children: [
          { index: true, element: <GoodsList /> },
          { path: ":id", element: <GoodsDetail /> }
        ]
      },
      {
        path: "/customer",
        element: <Customer />,
      },
      {
        path: "*",
        element: <NotFound />,
      },
    ]
  }
];

export default routes;

// src/App.tsx
import React from "react";
import { useRoutes } from "react-router-dom";
import routes from "./router/routes";

export default function App() {

  const element = useRoutes(routes);
  return (
    <>
      {element}
    </>
  );
}