前端
PythonJava运维数据库
React-Router(v6)
React-Router(v6)
  • Routers
    • createBrowserRouter
    • createHashRouter
    • createMemoryRouter
    • createStaticHandler
    • createStaticRouter
    • RouterProvider
    • StaticRouterProvider
  • Router 组件
    • BrowserRouter
    • HashRouter
    • MemoryRouter
    • NativeRouter
    • Router
    • StaticRouter
  • Route
    • Route
    • action
    • errorElement
    • hydrateFallbackElement
    • lazy
    • loader
    • shouldRevalidate
  • 组件
    • Await
    • Form
    • Link
    • Link(RN)
    • NavLink
    • Navigate
    • Outlet
    • Route
    • Routes
    • ScrollRestoration
  • 钩子函数
    • useActionData
    • useAsyncError
    • useAsyncValue
    • useBeforeUnload
    • useBlocker
    • useFetcher
    • useFetchers
    • useFormAction
    • useHref
    • useinRouterContext
    • useLinkcLickHandler
    • useLinkPressHandler
    • useLoaderData
    • useLocation
    • useMatch
    • useMatches
    • useNavigate
    • useNavigation
    • useNavigationType
    • useOutlet
    • useOutletContext
    • useParams
    • unstable_usePrompt
    • useResolvedPath
    • useRevalidator
    • useRouteError
    • useRouteLoaderData
    • useRoutes
    • useSearchParams
    • useSearchParams (RN)
    • useSubmit
    • unstable_useViewTransitionState
  • Utilities
    • Fetch 工具类
      • json
      • redirect
      • redirectDocument
      • replace
    • 其他工具类
      • createRoutesFromChildren
      • createRoutesFromElements
      • createSearchParams
      • defer
      • generatePath
      • isRouteErrorResponse
      • Location
      • matchPath
      • matchRoutes
      • renderMatches
      • resolvePath
  • 🥇Routers
    • Router
    • Route 配置
      • lazy
      • action
      • shouldRevalidate
      • loader
由 GitBook 提供支持
在本页
  • 动态路由
  • 可选路由
  • 通配符Splats
  • 默认子路由
  • loader
  • 使用defer
  • action
  • element/Component
  • errorElement/ErrorBoundary
  • lazy

这有帮助吗?

  1. Routers

Route 配置

路由是 React Router 应用程序中最重要的部分。它们将 URL 段与组件、loader和action耦合在一起。通过路由嵌套,使得复杂的应用程序布局和数据依赖关系变得简单且具有声明性。

const router = createBrowserRouter([
  {
    // 渲染组件
    element: <Team/>,

    // URL  => http://localhost:3000/teams/1
    path: "teams/:teamId",

    // 在组件呈现之前加载数据
    loader: async ({params}) => {
      return fetch(`/api/teams/${params.teamId}`)
    },

    // 在数据提交时执行的突变
    action: async ({request}) => {
      return updateFakeTeam(await request.formData());
    },

    // 发生错误时呈现的组件
    errorElement: <ErrorBounday/>
  }
])

动态路由

如果路由段以:开头,则它变成“动态段”。当路由与URL匹配时,动态段将从 URL 中解析并作为 params 提供给其他路由API。

const router = createBrowserRouter([
  {
    path: '/',
    element: <App/>,
    children: [
      {path: 'team/:teamId', element: <Team/>},
    ]
  }
])

function Component() {
  const params = useParams()
  return <div>{params.teamId}</div>
}

在一个路由段中可以有多个动态路由,例如:

const router = createBrowserRouter([
  {
    path: '/',
    element: <App/>,
    children: [
      {path: ':userId/team/:teamId', element: <Team/>},
    ]
  }
])

可选路由

通过在路由段的末尾添加一个?来让其变成可选的。例如让一个动态路由段变成可选路由。

const router = createBrowserRouter([
  {
    /**
    * http:localhost:3000/categories
    * http:localhost:3000/en/categories
    * http:localhost:3000/cn/categories
    */
    path: "/:lang?/categories",
    element: <Categories/>,
    loader: ({params}) => {},
    action: ({params}) => {}
  }
])

除了修饰动态路由段之外,还可以修饰静态路由段

const router = createBrowserRouter([
  {
    path: "/project/task?/:taskId",
    element: <Categories/>,
  }
])

通配符Splats

如果路由路径模式以/*结尾,那么它将匹配后面的任何字符,包括其他/字符。

const router = createBrowserRouter([
  {
    /**
     * http:localhost:3000/files
     * http:localhost:3000/files/one
     * http:localhost:3000/files/one/two
     */
    path: "/files/*",
    element: <Files/>,
    loader: ({params}) => {
      console.log(params["*"])  // one/two
    },
    action: ({params}) => {}
  }
])

function Files() {
  const params = useParams()
  console.log(params["*"])  // one/two
  return <div>Files</div>
}

默认子路由

当子路由中设置index: true的时候,该组件在你访问父路由的时候,它就会被默认渲染。因此该路由不需要设置额外的path属性。

const router = createBrowserRouter([
  {
    element: <Team/>,
    path: "/teams/:teamId",
    children: [
      {
        element: <TeamHome/>,
        index: true
      },
      {
        element: <TeamConfig/>,
        path: "home-config"
      }
    ]
  }
])

loader

路由加载器在组件加载之前被调用,向组件提供数据,在组件内通过useLoaderData钩子获取数据。

const router1 = createBrowserRouter([
  {
    element: <Team/>,
    path: "teams/:teamId",
    children: [
      {
        element: <TeamHome/>,
        index: true,
        loader: async ({params, request, context}) => {
          return fetch(`https://httpbin.org/get?username=zs&age=20&id={params.id}`).then(data => data.json())
        }
      }
    ]
  }
])

function TeamHome() {
  // 获取 loader 函数的返回值
  const loaderData = useLoaderData();
  return <div></div>
}
  • params:从动态路由中解析出来的字段。

  • request:获取请求实例。

当你在loader进行网络请求时,如果这个请求的过程很慢,它会阻碍路由的跳转以及视图的加载,直到你请求到了数据,路由才会跳转。为了解决这个问题,React Router 利用 React18 的 Suspense 通过 defer 相应实用工具和Await组件或useAsyncValue钩子进行数据获取。通过使用这些API,你可以解决以下两个问题:

  1. 你的数据不再在瀑布流上:文档->JavaScript->惰性加载路由和数据(并行)

  2. 你可以轻松地在回退渲染和等待数据之间切换。

使用defer

将你在loader中需要返回的数据使用defer包裹,视图渲染的部分通过Suspense和Aswit包裹。

此时,当你的网络请求很慢的情况下,它会展示一个loading状态。

或者你可以使用useAsyncValue钩子,但你需要将代码分离到另一个组件中:

interface IUser {
  name: string,
  age: number
}

function sleep(ms: number): Promise<IUser> {
  return new Promise(resolve => setTimeout(() => resolve({
    name: "zs", age: 20
  }), ms));
}

export function loader({params, request, context}: LoaderFunctionArgs) {
  return defer({
    user: sleep(1000)
  })
}

export const Component = () => {
  const data = useLoaderData() as { user: IUser };
  return (
    <div>
      <h1>welcome</h1>
      <React.Suspense fallback={<div>loading</div>}>
        <Await resolve={data.user} errorElement={
          <p>Error loading package location!</p>
        }>
          <User/>
        </Await>
      </React.Suspense>
    </div>
  );
};


function User() {
  const user = useAsyncValue() as IUser
  return (
    <p>
      Your name is {user.name}, age is {user.age}
    </p>
  );
}

现在,我们不必再等待请求到数据,才路由跳转,而是在开始路由跳转后立即开始数据请求,在此过程中,异步数据渲染的部分会展示你提供的loading。

此外,你可以根据是否包含await关键字来切换某些内容是否将被延迟。

action

当提交从Form、fetcher、submission发送到路由时调用的操作。

const router = createBrowserRouter([
  {
    element: <Team/>,
    path: "teams/:teamId",
    children: [
      {
        element: <TeamHome/>,
        index: true,
        loader: ({params}) => {
          return fetch(`/api/teams/${params.teamId}/home`).then(res => res.json())
        },
        action: async ({request}) => {
          const formData = await request.formData();
          return updateTeam(formData)
        }
      },
      {
        element: <Home/>,
        path: "home"
      }
    ]
  }
])

element/Component

当URL匹配时,需要呈现出的React组件。

<Route element={<Team />} path="/team" />

<Route Component={<Team />} path="/team" />

errorElement/ErrorBoundary

当组件在渲染中抛出异常,或者在loader或action中发生错误时,,此 React 组件将渲染你提供的错误提示组件。


const router = createBrowserRouter([
  {
    path: "/",
    element: <App/>,
    children: [
      {path: '/', element: <Home/>, errorElement: "页面渲染发生错误"},
      {path: "/about", element: <About/>},
      {path: "/profile", element: <Profile/>},
      {path: "/*", element: "404页面"}
    ]
  },
], {
  basename: "/webapp"
})

当你为该路由组件提供了errorElement属性后,React 错误边界捕获的异常组件渲染将会失效。

lazy

未来保持应用程序包较小,并支持路由的代码分割,每个路由都可以提供一个async函数来解决路由定义中的非路由匹配部分(loader、action、Component/element,ErrorBoundary/errorElement等等)。

const router = createBrowserRouter([
  {
    element: <Team/>,
    path: "teams/:teamId",
    children: [
      {
        lazy: () => import("../pages/team/home"),
        index: true,
      },
      {
        lazy: () => import("../pages/team/about"),
        path: "about"
      }
    ]
  }
])

在懒加载路由中,导出你想要为路由定义的属性:

export async function loader({request}) {
    let data = await fetchData(request);
    return json(data)
}

export function Team() {
    let data = useLoaderData()
    return <div>{data}</div>
}
上一页Router下一页lazy

最后更新于9个月前

这有帮助吗?

🥇