React使用Outlet实现路由跳转时局部刷新页面

Outlet是react-router-dom插件的一个组件,首先需要安装react-router-dom插件:
cnpm i react-router-dom --save

官方文档

应该在父路由元素中用来渲染其子路由元素。这允许在渲染子路由时显示嵌套的 UI。如果父路由完全匹配,则将渲染子索引路由;如果没有索引路由,则不渲染任何内容。

function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>

      {/* This element will render either <DashboardMessages> when the URL is
          "/messages", <DashboardTasks> at "/tasks", or null if it is "/"
      */}
      <Outlet />
    </div>
  );
}

function App() {
  return (
    <Routes>
      <Route path="/" element={<Dashboard />}>
        <Route
          path="messages"
          element={<DashboardMessages />}
          />
        <Route path="tasks" element={<DashboardTasks />} />
      </Route>
    </Routes>
  );
}

实现

效果演示

首页初始化状态:
在这里插入图片描述
进入/home且改变页面其他区域的状态:
在这里插入图片描述
点击去购物车的按钮,进入购物车页面,页面内容局部刷新,页面其他区域的状态不变:
在这里插入图片描述

代码

router.tsx:

import { createBrowserRouter } from 'react-router-dom'
import { OutletDemo } from '../grammar'
import { Cart, Home } from '../pages'

const router = createBrowserRouter([
  {
    path: '/',
    element: <OutletDemo />,
    children: [
      {
        path: 'home',
        element: <Home />,
      },
      {
        path: 'cart',
        element: <Cart />,
      },
    ],
  },
])
export default router

App.tsx:

import './App.css'
import { RouterProvider } from 'react-router-dom'
import router from './routes/router'

function App() {
  return (
    <>
      <RouterProvider router={router} />
    </>
  )
}

export default App

OutletDemo.tsx:
第82行插入Outlet组件

import { Outlet } from 'react-router-dom'
import React from 'react'
import {
  LaptopOutlined,
  NotificationOutlined,
  UserOutlined,
} from '@ant-design/icons'
import type { MenuProps } from 'antd'
import { Breadcrumb, Layout, Menu, theme } from 'antd'

const { Header, Content, Sider } = Layout

const items1: MenuProps['items'] = ['1', '2', '3'].map((key) => ({
  key,
  label: `nav ${key}`,
}))

const items2: MenuProps['items'] = [
  UserOutlined,
  LaptopOutlined,
  NotificationOutlined,
].map((icon, index) => {
  const key = String(index + 1)

  return {
    key: `sub${key}`,
    icon: React.createElement(icon),
    label: `subnav ${key}`,

    children: new Array(4).fill(null).map((_, j) => {
      const subKey = index * 4 + j + 1
      return {
        key: subKey,
        label: `option${subKey}`,
      }
    }),
  }
})

export const OutletDemo: React.FC = () => {
  const {
    token: { colorBgContainer, borderRadiusLG },
  } = theme.useToken()

  return (
    <Layout>
      <Header style={{ display: 'flex', alignItems: 'center' }}>
        <div className="demo-logo" />
        <Menu
          theme="dark"
          mode="horizontal"
          defaultSelectedKeys={['2']}
          items={items1}
          style={{ flex: 1, minWidth: 0 }}
        />
      </Header>
      <Layout>
        <Sider width={200} style={{ background: colorBgContainer }}>
          <Menu
            mode="inline"
            defaultSelectedKeys={['1']}
            defaultOpenKeys={['sub1']}
            style={{ height: '100%', borderRight: 0 }}
            items={items2}
          />
        </Sider>
        <Layout style={{ padding: '0 24px 24px' }}>
          <Breadcrumb style={{ margin: '16px 0' }}>
            <Breadcrumb.Item>Home</Breadcrumb.Item>
            <Breadcrumb.Item>List</Breadcrumb.Item>
            <Breadcrumb.Item>App</Breadcrumb.Item>
          </Breadcrumb>
          <Content
            style={{
              padding: 24,
              margin: 0,
              minHeight: 280,
              background: colorBgContainer,
              borderRadius: borderRadiusLG,
            }}
          >
            <Outlet />
          </Content>
        </Layout>
      </Layout>
    </Layout>
  )
}

Home.tsx:

import { useState } from 'react'
import { useNavigate, Link, Navigate } from 'react-router-dom'

export const Home = () => {
  const navigate = useNavigate()
  const [condition, setCondition] = useState(true)

  return (
    // <button onClick={() => navigate('/cart')}>
    //   Home
    // </button>
    <Link to="/cart">去购物车</Link>
    // condition ? (
    //   <Navigate to="/cart" replace={false}>
    //     去购物车
    //   </Navigate>
    // ) : (
    //   <div>不去</div>
    // )
  )
}

Cart.tsx:

export const Cart = () => {
  return <div>Cart</div>
}
React Router v6 中的 `<Outlet>` 组件是一个占位符组件,用于渲染父级路由器中嵌套的子路由。当一个父级路由器包含子路由,`<Outlet>` 组件用于在父级路由器中渲染子路由器的内容。 例如,如果我们有一个父级路由器 `/dashboard`,它包含两个子路由器 `/dashboard/overview` 和 `/dashboard/profile`,我们可以在父级路由器中使用 `<Outlet>` 组件来渲染这些子路由器的内容: ```jsx import { BrowserRouter as Router, Routes, Route, Link, Outlet } from 'react-router-dom'; function Dashboard() { return ( <div> <h1>Dashboard</h1> <nav> <ul> <li><Link to="overview">Overview</Link></li> <li><Link to="profile">Profile</Link></li> </ul> </nav> <Outlet /> </div> ); } function Overview() { return <h2>Overview</h2>; } function Profile() { return <h2>Profile</h2>; } function App() { return ( <Router> <Routes> <Route path="dashboard" element={<Dashboard />}> <Route path="overview" element={<Overview />} /> <Route path="profile" element={<Profile />} /> </Route> </Routes> </Router> ); } ``` 在上面的例子中,当用户访问 `/dashboard` 路径,`<Dashboard>` 组件会被渲染,并且 `<Outlet>` 组件会渲染子路由器的内容。当用户访问 `/dashboard/overview` 路径,`<Dashboard>` 组件仍然会被渲染,但是 `<Overview>` 组件会被渲染到 `<Outlet>` 组件中。同样,当用户访问 `/dashboard/profile` 路径,`<Dashboard>` 组件也会被渲染,但是 `<Profile>` 组件会被渲染到 `<Outlet>` 组件中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端吕小布

您的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值