likes
comments
collection
share

React Router v6 官方文档翻译 (八) ---- 新版新增功能汇总(上)

作者站长头像
站长
· 阅读数 21

React Router v6版本,听说又更新了一版,官网文档也更新了(6.4.2)。这里就汇总翻译一下文档更新的内容。

了解其他 React Router v6 的官网文档,可以看我本专栏往期的文章。

1、关于 Routers

API创建router对象:

createBrowserRouter

类型定义:

function createBrowserRouter(
  routes: RouteObject[],
  opts?: {
    basename?: string;
    window?: Window;
  }
): RemixRouter;

这个 API 用于使用js代码创建一个 History router。第二个属性是可选参数:

  • basename:相对路由根地址
  • window:重新指定window对象,常用于测试环境或者非浏览器环境

使用方式如下:

import {
  createBrowserRouter,
  RouterProvider,
} from "react-router-dom";

const router = createBrowserRouter([
  {
    path: "/",
    element: <Root />,
    loader: rootLoader,
    children: [
      {
        path: "team",
        element: <Team />,
        loader: teamLoader,
      },
    ],
  },
]);

ReactDOM.createRoot(document.getElementById("root")).render(
  <RouterProvider router={router} />
);

createHashRouter

使用方式同 createBrowserRouter,创建一个基于锚点导航的 router。

createMemoryRouter

memory router是一个能够自己管理 history stack 的 History router。常用于开发工具(例如StoryBook)、测试或非浏览器环境。

类型定义:

function createMemoryRouter(
  routes: RouteObject[],
  opts?: {
    basename?: string;
    initialEntries?: InitialEntry[];
    initialIndex?: number;
    window?: Window;
  }
): RemixRouter;

使用方式:

import {
  RouterProvider,
  createMemoryRouter,
} from "react-router-dom";
import * as React from "react";
import {
  render,
  waitFor,
  screen,
} from "@testing-library/react";
import "@testing-library/jest-dom";
import CalendarEvent from "./routes/event";

test("event route", async () => {
  const FAKE_EVENT = { name: "test event" };
  const routes = [
    {
      path: "/events/:id",
      element: <CalendarEvent />,
      loader: () => FAKE_EVENT,
    },
  ];

  const router = createMemoryRouter(routes, {
    initialEntries: ["/", "/events/123"],
    initialIndex: 1,
  });

  render(<RouterProvider router={router} />);

  await waitFor(() => screen.getByRole("heading"));
  expect(screen.getByRole("heading")).toHaveTextContent(
    FAKE_EVENT.name
  );
});

其中的参数:

  • initialEntries:初始化的 history stack
  • initialIndex:初始化显示的 history stack 的下标

RouterProvider

给上述创建router的API提供一个容器。其有第二个参数 fallbackElement={<SpinnerOfDoom />},可以提供一个在路由加载过程中 loading的自定义组件。

2、关于 Route 组件

添加新属性 loader

路由在渲染之前加载的加载器。当路由跳转时,loader函数会异步的执行,并且在目标路由组件中可以获取到。

使用方式:

 {
    element: <Team />,
    path: ":teamId",
    loader: async ({ params }) => {
      return fetch(`/api/teams/${params.teamId}.json`);
    },
  },

参数 params 是路由参数。可以返回任何你想要的内容,推荐使用 fetch 或者 Promise。

loader 加载的数据可以在跳转之后的界面 通过 useLoaderData 获取。使用方式见下面 hooks 的更新内容。

添加新属性 action

提供一种路由切换时触发的方法。该方式允许在路由跳转时推送一个 ajax 请求出去。

使用方式:

// 定义
<Route
  path="/song/:songId/edit"
  element={<EditSong />}
  action={async ({ params, request }) => {
    let formData = await request.formData();
    return fakeUpdateSong(params.songId, formData);
  }}
  loader={({ params }) => {
    return fakeGetSong(params.songId);
  }}
/>

// forms
<Form method="post" action="/songs" />;
<fetcher.Form method="put" action="/songs/123/edit" />;

// imperative submissions
let submit = useSubmit();
submit(data, {
  method: "delete",
  action: "/songs/123",
});
fetcher.submit(data, {
  method: "patch",
  action: "/songs/123/edit",
});

触发方式为非GET类的请求,并提供两个参数:

  • params 路由动态参数
  • request fetch请求的实例

errorElement

只适用于API动态创建的router。使用方式:

<Route
  path="/invoices/:id"
  // if an exception is thrown here
  loader={loadInvoice}
  // here
  action={updateInvoice}
  // or here
  element={<Invoice />}
  // this will render instead of `element`
  errorElement={<ErrorBoundary />}
/>;

function Invoice() {
  return <div>Happy {path}</div>;
}

function ErrorBoundary() {
  let error = useRouteError();
  console.error(error);
  // Uncaught ReferenceError: path is not defined
  return <div>Dang!</div>;
}

提供一种路由跳转错误后的补救方案。在action、loader或者组件渲染过程中抛出错误后,可以在这里捕获并代替显示自定义的错误界面。

shouldRevalidate

作为一个优化项,用于对loader做校验。他是一个函数,在路由 loader 获取数据之前调用,该函数返回一个布尔值,如果返回布尔值,本次 loader 函数将不会调用,界面数据不会改变。

使用方式:

<Route
  path="meals-plans"
  element={<MealPlans />}
  loader={loadMealPlans}
  shouldRevalidate={({ currentUrl }) => {
    // only revalidate if the submission originates from
    // the `/meal-plans/new` route.
    return currentUrl.pathname === "/meal-plans/new";
  }}
>
  <Route
    path="new"
    element={<NewMealPlanForm />}
    // `loadMealPlans` will be revalidated after
    // this action...
    action={createMealPlan}
  />
  <Route
    path=":planId/meal"
    element={<Meal />}
    // ...but not this one because origin the URL
    // is not "/meal-plans/new"
    action={updateMeal}
  />
</Route>

3、关于路由组件

Await

是一种类似于 React 路由懒加载(lazy)的工具。使用方式如下:

import { Await, useLoaderData } from "react-router-dom";

function Book() {
  const { book, reviews } = useLoaderData();
  return (
    <div>
      <h1>{book.title}</h1>
      <p>{book.description}</p>
      <React.Suspense fallback={<ReviewsSkeleton />}>
        <Await
          resolve={reviews}
          errorElement={
            <div>Could not load reviews 😬</div>
          }
          children={(resolvedReviews) => (
            <Reviews items={resolvedReviews} />
          )}
        />
      </React.Suspense>
    </div>
  );
}

Form

v6版路由,对于 plain HTML form 进行了一个包装。目前仅仅在使用 API 创建路由实例的场景中使用。

import { Form } from "react-router-dom";

function NewEvent() {
  return (
    <Form method="post" action="/events">
      <input type="text" name="title" />
      <input type="text" name="description" />
      <button type="submit">Create</button>
    </Form>
  );
}

属性参数介绍:

  • action:form submit 的 url。和原生form唯一不同的是,他的默认url是最近匹配到的相对路由
  • method:表单提交的方法
  • replace:改变 history stack 的切换方式
  • relative:设置相对路由的根路由
  • reloadDocument:跳过 React Router 并使用浏览器的内置行为提交表单

综合使用案例:

总结:action 可以接受 element 组件中传入的请求实例,在action中进行使用。而紧接着,element 组件中,又可以通过 useLoaderData 使用 loader 里加载进来的数据。

<Route
  path="/projects/:id"
  element={<Project />}
  loader={async ({ params }) => {
    return fakeLoadProject(params.id)
  }}
  action={async ({ request, params }) => {
    switch (request.method) {
      case "put": {
        let formData = await request.formData();
        let name = formData.get("projectName");
        return fakeUpdateProject(name);
      }
      case "delete": {
        return fakeDeleteProject(params.id);
      }
      default {
        throw new Response("", { status: 405 })
      }
    }
  }}
/>;

function Project() {
  let project = useLoaderData();

  return (
    <>
      <Form method="put">
        <input
          type="text"
          name="projectName"
          defaultValue={project.name}
        />
        <button type="submit">Update Project</button>
      </Form>

      <Form method="delete">
        <button type="submit">Delete Project</button>
      </Form>
    </>
  );
}

ScrollRestoration

用于在浏览器 location变化后,保持滚动条的位置。仅仅在 API 创建路由对象时有效。

推荐在根路由中使用,使用方式:

import { ScrollRestoration } from "react-router-dom";

function RootRouteComponent() {
  return (
    <div>
      {/* ... */}
      <ScrollRestoration
        getKey={(location, matches) => {
          // default behavior
          return location.key;
        }}
      />
    </div>
  );
}

参数:

  • getKey:React Router 缓存滚动位置的key
  • preventScrollReset:当创建一个新的 scroll key时,页面滚动位置会被重置在顶部。你可以将该参数设置为 true 来阻止页面被重置回顶部

由于篇幅过长,新版文档的hooks和内置方法介绍放到下期进行。下篇在这里:React Router v6 官方文档翻译 (九) ---- 新版新增功能汇总(下)

转载自:https://juejin.cn/post/7158348116881014815
评论
请登录