React 路由使用示例详解

目录
  • Router
  • 简单路由
  • 嵌套路由
  • 未匹配路由
  • 路由传参数
  • 索引路由
  • 活动链接
  • 搜索参数
  • 自定义行为
  • useNavigate
  • 参考资料

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 页面展示时,是个a标签 */}
        <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 页面展示时,是个a标签 */}
        <Link className ='link' to='/Tab1'> Tab1</Link>
        <Link className ='link' to='/Tab2'> Tab2 </Link>
      </nav>
      {/* 此时尚不能实现共享APP UI的同时渲染出 Tab1 和 Tab2,还需要使用 <Outlet/>
        保证父路由,在子路由交换时,仍然存在
      */}
      <Outlet/>
    </div>
    );
}

///index.js
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
       <Route path='/' element={<App />} >
          {/* 孩子路由,url为:  / + 孩子的path */}
          <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 />} >
          {/* 孩子路由,url为:  / + 孩子的path */}
          <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}>
                           {/*子路由形如:'/Tab2/20220103' */}
                            <Link to={`/Tab2/${item.id}`}>{item.content}</Link>
                        </li>
                    ))
                }
            </ul>
           {/*渲染一个子路由的元素*/}
            <Outlet />
        </div>
    );
}

///注册列表项的子路由
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <Routes>
      <Route path='/' element={<App />} >
          {/* 孩子路由,url为:  / + 孩子的path */}
          <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 />} >
          {/* 孩子路由,url为:  / + 孩子的path */}
          <Route path='Tab1' element={<Tab1 />} /> 

          <Route path='Tab2' element={<Tab2 />} >
            {/*索引路由 有index 无path*/}
            <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}>
                            {/* <Link to={`/Tab2/${item.id}`}>{item.content}</Link> */}
                            <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}>
                            {/* <Link to={`/Tab2/${item.id}`}>{item.content}</Link> */}
                            <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 路由使用内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 使用React-Router实现前端路由鉴权的示例代码

    React-Router 是React生态里面很重要的一环,现在React的单页应用的路由基本都是前端自己管理的,而不像以前是后端路由,React管理路由的库常用的就是就是 React-Router .本文想写一下 React-Router 的使用,但是光介绍API又太平淡了, 而且官方文档已经写得很好了 ,我这里就用一个常见的开发场景来看看 React-Router 是怎么用的吧.而我们一般的系统都会有用户访问权限的限制,某些页面可能需要用户具有一定的权限才能访问.本文就是用 React-Ro

  • 详解react-navigation6.x路由库的基本使用

    目录 react-native项目初始化 安装react-native项目 react-navigation路由库安装 使用路由库 路由跳转与路由传参 设置路由标题 自定义标题组件 标题按钮 react-native项目初始化 打开cmd,cd到在要进行rn项目建立的文件夹. npx react-native init testRN 这里我的项目名设置为testRN,可以自行设定. 安装react-native项目 连接安卓虚拟机或者usb调试真机,cd进创建好的项目根目录,yarn andro

  • 详解前端路由实现与react-router使用姿势

    路由 对于有过SPA开发经验的人来说,路由这个名词并不陌生,前端的路由和后端的路由在实现技术上不一样,但是原理都是一样的.在 HTML5 的 history API 出现之前,前端的路由都是通过 hash 来实现的,hash 能兼容低版本的浏览器.它的 URI 规则中需要带上 #.Web 服务并不会解析 hash,也就是说 # 后的内容 Web 服务都会自动忽略,但是 JavaScript 是可以通过 window.location.hash 读取到的,读取到路径加以解析之后就可以响应不同路径的

  • react-router v4如何使用history控制路由跳转详解

    前言 距离React Router v4 正式发布也已经挺久了,这周把一个React的架子做了升级,之前的路由用的还是v2.7.0版的,所以决定把路由也升级下,正好"尝尝鲜"... 江湖传言,目前官方同时维护 2.x 和 4.x 两个版本.(ヾ(。ꏿ﹏ꏿ)ノ゙咦,此刻相信机智如我的你也会发现,ReactRouter v3 去哪儿了?整丢了??巴拉出锅了???敢不敢给我个完美的解释!?)事实上 3.x 版本相比于 2.x 并没有引入任何新的特性,只是将 2.x 版本中部分废弃 API 的

  • react-router4 嵌套路由的使用方法

    react我自己还在摸索学习中,今天正好学习一下react-router4 嵌套路由的使用方法,顺便留着笔记 先直接贴代码 import React from 'react'; import ReactDOM from 'react-dom'; import { HashRouter as Router, Route, Switch} from 'react-router-dom'; import createBrowserHistory from 'history/createBrowserH

  • React 路由使用示例详解

    目录 Router 简单路由 嵌套路由 未匹配路由 路由传参数 索引路由 活动链接 搜索参数 自定义行为 useNavigate 参考资料 Router react-router-dom是一个处理页面跳转的三方库,在使用之前需要先安装到我们的项目中: # npm npm install react-router-dom@6 #yarn yarn add react-router-dom@6 简单路由 使用路由时需要为组件指定一个路由的path,最终会以path为基础,进行页面的跳转.具体使用先看

  • react 路由Link配置详解

    1.Link的to属性 (1)放置路由路径 (2)放置对象,且为规定格式 {pathname:"/xx",search:'?键值对',hash:"#xxx",state:{键值对}} 会自动将pathname.search.hash拼接在url路径上,state为传入的参数 可通过输出props查看对象内的信息 this.props.location.state.键名获取state内的数据 2.Link的replace属性 添加replace将跳转前的上一个页面替换

  • React Redux应用示例详解

    目录 一 React-Redux的应用 1.学习文档 2.Redux的需求 3.什么是Redux 4.什么情况下需要使用redux 二.最新React-Redux 的流程 安装Redux Toolkit 创建一个 React Redux 应用 基础示例 Redux Toolkit 示例 三.使用教程 安装Redux Toolkit和React-Redux​ 创建 Redux Store​ 为React提供Redux Store​ 创建Redux State Slice​ 将Slice Reduc

  • react使用useImperativeHandle示例详解

    目录 1.前言 2.useImperativeHandle初探 3.获取元素的几种方式 3.1 useRef:获取组件内部元素 3.2 forwardRef:父组件获取子组件内部的一个元素 3.3 useImperativeHandle:父组件可以获取/操作儿子组件多个元素 1.前言 相比大家看到useImperativeHandle会感到十分陌生,但部分开源代码经常会出现它的身影,网上查阅的资料也是含糊不清.经过一翻资料查询,终于摸清了一点,现在分享给各位爷. 2.useImperativeH

  • React Hook用法示例详解(6个常见hook)

    1.useState:让函数式组件拥有状态 用法示例: // 计数器 import { useState } from 'react' const Test = () => { const [count, setCount] = useState(0); return ( <> <h1>点击了{count}次</h1> <button onClick={() => setCount(count + 1)}>+1</button> &l

  • react路由配置方式详解

    本文介绍了react路由配置,最近刚开始学,分享给大家,顺便给自己留个笔记. 包含了LInk跳转以及js触发跳转并传参. 这是项目的目录结构,主要的代码都在src目录下,src下面新建一个containers文件夹放我们的一些组件,router文件夹是配置路由用的. 按照顺序来写:detail文件夹下的代码 import React from 'react' class Detail extends React.Component { render() { return ( <p>Detail

  • vue 2.0路由之路由嵌套示例详解

    前言 vue一个重要的方面就是路由,下面是自己写的一个路由的例子分享给大家供大家参考学习,下面来看看详细的介绍. 方法如下: 1.引入依赖库就不必再说 2.创建组件 两种写法 第一种:间接 <template id="home"> <div> <h1>Home</h1> <p>{{msg}}</p> </div> </template> var About = Vue.extend({ te

  • ReactQuery系列React Query 实践示例详解

    目录 引言 客户端状态 vs 服务端状态 React Query 关于默认行为的解释 使用React Query DevTools 把query key理解成一个依赖列表 一个新的缓存入口 把服务端状态和客户端状态分开 enabled属性是很强大的 创建自定义hook 引言 当2018年GraphQL特别是Apolllo Client开始流行之后,很多人开始认为它将替代Redux,关于Redux是否已经落伍的问题经常被问到. 我很清晰地记得我当时对这些观点的不理解.为什么一些数据请求的库会替代全

  • React路由拦截模式及withRouter示例详解

    目录 一.路由拦截 二.路由模式 三.withRouter 一.路由拦截 在前面两篇 路由博客基础上,我们将ReactRouter.js的我的profile路由设置成路由拦截的: <Route path="/profile" render={() => isAuth() ? <Profile/> : <Redirect to="/login"></Redirect> }></Route> 新建Logi

  • react redux及redux持久化示例详解

    目录 一.react-redux 二.redux持久化 一.react-redux react-redux依赖于redux工作. 运行安装命令:npm i react-redux: 使用: 将Provider套在入口组件处,并且将自己的store传进去: import FilmRouter from './FilmRouter/index' import {Provider} from 'react-redux' import store from './FilmRouter/views/red

随机推荐