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 directly
throw context;
}
let router = createStaticRouter(dataRoutes, context);
return ReactDOMServer.renderToString(
<React.StrictMode>
<StaticRouterProvider router={router} context={context} />
</React.StrictMode>
);