react-router 為了滿足開發者更多路由歷史存儲場景,提供了以下幾種模式:
-
瀏覽器原生歷史記錄
-
瀏覽器 hash
-
內存型
-
服務端記錄
以上實現分別對應于一下 API 實現:
-
createBrowserRouter:瀏覽器提供的歷史管理。
-
createHashRouter:基于 hash 的路由管理,#hello,但是呢通常 # 又可以作為錨鏈接。
-
createMemoryRouter:內存型路由,路由的管理存儲在內存中。
-
createStaticRouter:SSR 服務端的。
1.?createBrowserRouter
通過瀏覽器原生路由進行路由態管理,頁面跳轉通過 pushState、popState 方法實現。
import * as React from "react";
import * as ReactDOM from "react-dom";
import {createBrowserRouter,RouterProvider} from "react-router-dom";import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";const router = createBrowserRouter([{path: "/",element: <Root />,loader: rootLoader,children: [{path: "team",element: <Team />,loader: teamLoader,},],},
]);ReactDOM.createRoot(document.getElementById("root")).render(<RouterProvider router={router} />
);
需要注意的是,使用 browserRouter,一般都需要使用類似 Nginx 做靜態資源代理,另外需要注意 404 的情況,一般都需要添加 try_files 處理。
location / {try_files $uri /index.html;
}
2.?createHashRouter(不推薦)
請注意,這個方法非常不推薦,他的用武之地就在于,我們沒有 Nginx 作為靜態資源代理,我們可能就無法使用瀏覽器歷史作為我們路由狀態的存儲,這時可以選擇 hash router 方案,但是注意,真的非常不推薦,除非是你自己的個人項目。
import * as React from "react";
import * as ReactDOM from "react-dom";
import {createHashRouter,RouterProvider} from "react-router-dom";import Root, { rootLoader } from "./routes/root";
import Team, { teamLoader } from "./routes/team";const router = createHashRouter([{path: "/",element: <Root />,loader: rootLoader,children: [{path: "team",element: <Team />,loader: teamLoader,},],},
]);ReactDOM.createRoot(document.getElementById("root")).render(<RouterProvider router={router} />
);
3.?createMemoryRouter
用于創建一個內存型路由,路由表與歷史記錄棧存儲在內存中,當頁面刷新時,路由信息丟失。
import * as React from "react";
import * as ReactDOM from "react-dom";
import {createMemoryRouter,RouterProvider} from "react-router-dom";import CalendarEvent from "./routes/calendarEvent";const routes = [{path: "/events/:id",element: <CalendarEvent />,loader: () => FAKE_EVENT,},
];const router = createMemoryRouter(routes, {initialEntries: ["/", "/events/123"],initialIndex: 1,
});ReactDOM.createRoot(document.getElementById("root")).render(<RouterProvider router={router} />
);
其實這種內存型歷史記錄,我們自己通過狀態管理都能夠輕松實現,他這就類似于我們定義了集中狀態,然后當狀態更新時渲染不同頁面。而這里只是多了一些關于路由操作方法的實現,比如:push、pop 等。
4.?createStaticRouter
如果我們需要實現服務端渲染,那么在服務端的路由處理則需要使用該 API,因為我們知道客戶端的路由是基于瀏覽器的 history,而服務端是沒有瀏覽器環境的。
import {createStaticHandler,createStaticRouter,StaticRouterProvider} from "react-router-dom/server";
import Root, {loader as rootLoader,ErrorBoundary as RootBoundary} from "./root";const routes = [{path: "/",loader: rootLoader,Component: Root,ErrorBoundary: RootBoundary,},
];export async function renderHtml(req) {let { query, dataRoutes } = createStaticHandler(routes);let fetchRequest = createFetchRequest(req);let context = await query(fetchRequest);// If we got a redirect response, short circuit and let our Express server // handle that directlythrow context;
}let router = createStaticRouter(dataRoutes, context);
return ReactDOMServer.renderToString(<React.StrictMode><StaticRouterProvider router={router} context={context} /></React.StrictMode>
);