React 路由使用

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 (
    

路由练习

); } ///路由页面1 export default function Tab1(params) { return ( // 文档中,
元素是唯一的,所以不能出现一个以上的
元素

我是Tab1

); } ///路由页面2 export default function Tab2(params) { return (

我是Tab2

); } ///在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( } /> ///兄弟路由 } />///兄弟路由 } />///兄弟路由 );

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

[图片上传失败...(image-e7e5d4-1654521601103)]

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

嵌套路由

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

Outlet渲染一个子路由的元素

import {Link,Outlet} from 'react-router-dom'
function App() {
  return (
    

路由练习

{/* 此时尚不能实现共享APP UI的同时渲染出 Tab1 和 Tab2,还需要使用 保证父路由,在子路由交换时,仍然存在 */}
); } ///index.js const root = ReactDOM.createRoot(document.getElementById('root')); root.render( } > {/* 孩子路由,url为: / + 孩子的path */} } /> } /> );

最终效果如下图:

[图片上传失败...(image-491108-1654521601104)]

未匹配路由

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

root.render(
  
    
      
      } >
          {/* 孩子路由,url为:  / + 孩子的path */}
          } /> 
          } />
          
            未匹配到路由时,会跳转此处。
          

} />
);

效果如图:

[图片上传失败...(image-c2afa2-1654521601104)]

路由传参数

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

///模拟数据
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 (
        
    { list.map((item) => (
  • {/*子路由形如:'/Tab2/20220103' */} {item.content}
  • )) }
{/*渲染一个子路由的元素*/}
); } ///注册列表项的子路由 root.render( } > {/* 孩子路由,url为: / + 孩子的path */} } /> } > }/> 未匹配到该路由请先设置路由页面

} />
); ///定义Tab2子组件 ItemDetail import { useParams } from 'react-router-dom' export function ItemDetail() { //点击每一项的链接,注意:URL 发生了变化,但新的组件尚未显示 ///需要父组件中添加 ///HOOK 获取路由中的参数,形如{itemId:'20220102'} let params = useParams() let content = findTodoItem(parseInt(params.itemId)).content return (

笔记详情

这是我于{params.itemId},记录的笔记他的内容为{content}

) }

索引路由

当我们切换至Tab1再切回Tab2后,笔记详情页面将空白。

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

root.render(
  
    
      
      } >
          {/* 孩子路由,url为:  / + 孩子的path */}
          } /> 

          } >
            {/*索引路由 有index 无path*/}
            请选择一个笔记查看它的详情 

}/> }/> 未匹配到该路由请先设置路由页面

} />
);

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

活动链接

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

export default function Tab2(params) {
    let list = getTodoList()
    return (
        
    { list.map((item) => (
  • {/* {item.content} */} ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content}
  • )) }
); }

搜索参数

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

export default function Tab2(params) {
    let list = getTodoList()
    ///和React.useState很像
    let [searchParams, setSearchParams] = useSearchParams();
    return (
        
{/* 搜索框: 随着输入设置搜索参数 */} { let text = event.target.value if (text) { setSearchParams({text}) } else { setSearchParams({}) } } } />
    { list.filter((item)=>{ let txt = searchParams.get('text') if (!txt) return true return item.content.startsWith(txt) }) .map((item) => (
  • {/* {item.content} */} ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content}
  • )) }
); }

随着我们输入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 
}
//2. 替换 `tab1`、`tab2`的link or Navlink
 Tab1 
 Tab2 
//3. 替换列表项的link or Navlink
 
  • ({ color : isActive ? "red" : "" }) } to={`/Tab2/${item.id}`}> {item.content}
  • useNavigate

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

    export function ItemDetail() {
        //点击每一项的链接,注意:URL 发生了变化,但新的组件尚未显示
        ///需要父组件中添加
        let params = useParams()
        let content = findTodoItem(parseInt(params.itemId)).content
        ///返回函数
        let navigate = useNavigate()
        ///获取搜索字段
        let location = useLocation()
        return (
            

    笔记详情

    这是我于{params.itemId}记录的笔记,内容为{content}

    ) } // src/data.jsx export function deleteTodoItem(params) { dataList = dataList.filter((value)=>value.id !== parseInt(params)) }

    参考资料

    https://reactrouter.com/docs/en/v6/getting-started/tutorial

    你可能感兴趣的:(React 路由使用)