文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

React 路由使用示例详解

2024-04-02 19:55

关注

Router

react-router-dom是一个处理页面跳转的三方库,在使用之前需要先安装到我们的项目中:

# npm
npm install react-router-dom@6
#yarn
yarn add react-router-dom@6

简单路由

使用路由时需要为组件指定一个路由的path,最终会以path为基础,进行页面的跳转。具体使用先看个简单示例,该示例比较简单就是两个Tab页面的来回切换。

///导入路由
import {Link} from 'react-router-dom'
function App() {
  return (
    <div>
      <h1>路由练习</h1>
      <nav>
        {}
        <Link className ='link' to='/Tab1'> Tab1</Link> ///覆盖:渲染tab1组件
        <Link className = 'link' to='/Tab2'> Tab2 </Link> ///覆盖:渲染tab2组件
      </nav>
    </div>
    );
}
///路由页面1
export default function Tab1(params) {
    return (
        // 文档中,<main> 元素是唯一的,所以不能出现一个以上的 <main> 元素
        <main style={{ padding: "1rem 0" }}>
          <h2>我是Tab1</h2>
        </main>
      );
}
///路由页面2
export default function Tab2(params) {
    return (
        <main style={{ padding: "1rem 0" }}>
          <h2>我是Tab2</h2>
        </main>
      );
}
///在index.js中配置路由
import {BrowserRouter,Routes,Route} from 'react-router-dom'
import Tab1 from './pages/Tab1.jsx'
import Tab2 from './pages/Tab2.jsx'

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
     <Routes>
       <Route path = '/' element = {<App/>} /> ///兄弟路由
       <Route path = '/Tab1' element = {<Tab1/>} />///兄弟路由
       <Route path = '/Tab2' element = {<Tab2/>} />///兄弟路由
     </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

最终交互时,上述路由配置会出现彼此覆盖的情况,如下图:

为了保证App组件,不会在Tab1Tab2切换时被覆盖需要使用嵌套路由。

嵌套路由

嵌套路由,可以保证子路由共享父路由的界面而不会覆盖。为此React提供了Outlet组件,将其用于父组件中可以为子路由的元素占位,并最终渲染子路由的元素。

Outlet渲染一个子路由的元素

import {Link,Outlet} from 'react-router-dom'
function App() {
  return (
    <div>
      <h1>路由练习</h1>
      <nav>
        {}
        <Link className ='link' to='/Tab1'> Tab1</Link> 
        <Link className ='link' to='/Tab2'> Tab2 </Link>
      </nav>
      {}
      <Outlet/>
    </div>
    );
}

///index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
       <Route path='/' element={<App />} >
          {}
          <Route path='Tab1' element={<Tab1 />} /> 
          <Route path='Tab2' element={<Tab2 />} />
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

最终效果如下图:

未匹配路由

通过path='*',实现没有其他路由匹配时,对其进行匹配。

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
      <Route path='/' element={<App />} >
          {}
          <Route path='Tab1' element={<Tab1 />} /> 
          <Route path='Tab2' element={<Tab2 />} />
          <Route path = '*' element={<p>
            未匹配到路由时,会跳转此处。
          </p>} />
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

效果如图:

路由传参数

通过路由传递参数到组件中

///模拟数据
const dataList = [
    {
        id:20220101,
        content:'笔记1'
    },
    {
        id:20220102,
        content:'笔记2'
    },
    {
        id:20220103,
        content:'笔记3'
    },
]
export default function getTodoList(params) {
    return dataList
}

export function findTodoItem(params) {
    return dataList.find((value)=>value.id === params)
}
///组件Tab2中定义列表
export default function Tab2(params) {
    let list = getTodoList()
    return (
        <div>
            <ul>
                {
                    list.map((item) => (
                        <li key={item.id}>
                           {}
                            <Link to={`/Tab2/${item.id}`}>{item.content}</Link>
                        </li>
                    ))
                }
            </ul>
           {}
            <Outlet />
        </div>
    );
}

///注册列表项的子路由
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
      <Route path='/' element={<App />} >
          {}
          <Route path='Tab1' element={<Tab1 />} /> 
          <Route path='Tab2' element={<Tab2 />} >
            <Route path=':itemId' element={<ItemDetail/>}/>
          </Route>
          <Route path = '*' element={<p>未匹配到该路由请先设置路由页面 </p>} />
        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

///定义Tab2子组件 ItemDetail
import { useParams } from 'react-router-dom'
export function ItemDetail() {
    //点击每一项的链接,注意:URL 发生了变化,但新的组件尚未显示
    ///需要父组件中添加<Outlet>
    ///HOOK 获取路由中的参数,形如{itemId:'20220102'}
    let params = useParams()
    let content = findTodoItem(parseInt(params.itemId)).content
    return (
        <div>
            <h2>笔记详情</h2>
            <p>这是我于{params.itemId},记录的笔记他的内容为{content}</p>
        </div>
    )
}

最终效果:

索引路由

当我们切换至Tab1再切回Tab2后,笔记详情页面将空白,效果如下:

可以通过索引路由填补空白,具体只需:

root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
      <Route path='/' element={<App />} >
          {}
          <Route path='Tab1' element={<Tab1 />} /> 

          <Route path='Tab2' element={<Tab2 />} >
            {}
            <Route index element={<p>请选择一个笔记查看它的详情 </p>}/>
            <Route path=':itemId' element={<ItemDetail/>}/>
          </Route>
          
          <Route path = '*' element={<p>未匹配到该路由请先设置路由页面 </p>} />

        </Route>
      </Routes>
    </BrowserRouter>
  </React.StrictMode>
);

如此当我们重复上述操作时便会呈现如下效果:

当父路由匹配,但其他子路由都不匹配时,由索引路由匹配。索引路由是父路由的默认子路由。 当用户尚未单击导航列表中的一项时,会呈现索引路由。

活动链接

Link功能一致,差异是可以设置点击后的颜色

export default function Tab2(params) {
    let list = getTodoList()
    return (
        <div>
            <ul>
                {
                    list.map((item) => (
                        <li key={item.id}>
                            {}
                            <NavLink style = { ({isActive})=> ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content} </NavLink>
                        </li>
                    ))
                }
            </ul>
            <Outlet />
        </div>
    );
}

搜索参数

搜索参数类似于 URL 参数,形如/login?success=1

export default function Tab2(params) {
    let list = getTodoList()
    ///和React.useState很像
    let [searchParams, setSearchParams] = useSearchParams();
    return (
        <div>
            {}
            <input type="text" onChange = { (event)=>{
                let text = event.target.value
                if (text) {
                    setSearchParams({text})
                } else {
                    setSearchParams({})
                }
            } } />

            <ul>
                { list.filter((item)=>{
                    let txt = searchParams.get('text')
                    if (!txt) return true
                    return item.content.startsWith(txt)
                })
                    .map((item) => (
                        <li key={item.id}>
                            {}
                            <NavLink style = { ({isActive})=> ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content} </NavLink>
                        </li>
                    ))
                }
            </ul>

            <Outlet />
        </div>
    );
}

随着我们输入apple, 路由的地址将变为/Tab2?text=apple触发路由重新呈现。

当我们在输入框输入字符时,便会触发列表的过滤显示:

自定义行为

上述UI在交互过程中,当我们点击Tab1Tab2进行切换时,或者点击appleappet时,会出现输入框被清空,且列表不再被过滤的问题。

react-router提供了useLocation方法,它返回浏览器显示的url信息。通过它可以获取浏览器url中的搜索参数,从而进行暂存,在具体组件内,可以通过useSearchParams获取到暂存的值。具体方式,通过自定义组件包装NavLinkLink来实现。

///1.自定义`QueryLink`组件
import React, { Component } from 'react';
import { useLocation,NavLink } from "react-router-dom";
export default function QueryLink({to,...props}) {
  ///代表当前浏览器显示的url
  // location内容:{pathname: '/Tab2', search: '?text=ad', hash: '', state: null, key: 'dhvg8xme'}
  let location = useLocation()
  // to = '/Tab2?text=ad'
  return <NavLink to={to+location.search} {...props} />
}
//2. 替换 `tab1`、`tab2`的link or Navlink
<QueryLink className ='link' to='/Tab1'> Tab1</QueryLink> 
<QueryLink className ='link' to='/Tab2'> Tab2 </QueryLink>
//3. 替换列表项的link or Navlink
 <li key={item.id}>
   <QueryLink style = { ({isActive})=> ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content} </QueryLink>
 </li>

useNavigate

上述示例中,路由的切换采用Link或者NavLink,但当我们的页面元素不使用Link时,比如使用Button,此时便需要使用采用useNavigate。同上可以配合useLocation保存搜索字段。

export function ItemDetail() {
    //点击每一项的链接,注意:URL 发生了变化,但新的组件尚未显示
    ///需要父组件中添加<Outlet>
    let params = useParams()
    let content = findTodoItem(parseInt(params.itemId)).content
    ///返回函数
    let navigate = useNavigate()
    ///获取搜索字段
    let location = useLocation()
    return (
        <div>
            <h2>笔记详情</h2>
            <p>这是我于{params.itemId}记录的笔记,内容为{content}</p>
            <button onClick = {
                (e)=>{
                    deleteTodoItem(params.itemId)
                    navigate('/Tab2/'+location.search)
                }
            }>
                删除笔记
            </button>
        </div>
    )
}
// src/data.jsx
export function deleteTodoItem(params) {
    dataList = dataList.filter((value)=>value.id !== parseInt(params)) 
}

参考资料

reactrouter.com/docs/en/v6/…

到此这篇关于React 路由使用的文章就介绍到这了,更多相关React 路由使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

到此这篇关于React 路由使用示例详解的文章就介绍到这了,更多相关React 路由使用内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯