react-router-dom
- 官网
- 安装依赖
yarn add react-router-dom
几个路由相关组件
-
BrowserRouter
- 最外层router组件,基于h5的historyapi
-
HashRouter
- 最外层router组件,基于url的hashChagne
-
Route组件
- 属性
path
匹配的路径,默认模糊匹配 - 属性
component
组件名 - 属性
render
渲染组件,和componet二者选择一个 - 属性
exact
精确匹配
- 属性
-
Link组件
- to 链接url地址
- exact 精确匹配
-
NavLink 组件
- 路由跳转组件,比Link功能多
- activeStyle 选中状态的样式
- activeClassName 选中状态的类名,默认active
-
Switch组件
- 包裹在Route组件外层,只会匹配route中匹配的第一个,一般写404路由时候会加上该组件
-
综合使用
import { Route, Switch, BrowserRouter} from 'react-router-dom';
import React from 'react'
import HomePage from './HomePage'
import AboutPage from './AboutPage'
function notFoundPage() {
return <div>404page</div>
}
export default function Routes() {
return (
<div>
<BrowserRouter>
<NavLink to="/" exact activeStyle={{border: '1px solid yellow'}}>首页</NavLink>
|
<NavLink to="/about" activeStyle={{border: '1px solid green'}}>关于</NavLink>
<Switch>
{/* component写法 */}
<Route path="/" exact component={HomePage} />
<Route path="/about" exact component={AboutPage} />
<Route component={notFoundPage} />
{/* render写法 */}
<Route path="/" exact render = {() => <HomePage/>} />
<Route path="/about" render = {() => <AboutPage/>} />
<Route render = {() => <NotFoundPage/>} />
</Switch>
</BrowserRouter>
</div>
)
}
组件用componet 有些默认参数
组件内部默认props:
- history
- length 历史记录长度
- go(n) 进行n步
- goBack 返回上一步
- goFoward 前进一步
- push 增加历史记录
- replace 不增加历史记录
- location
- pathname 当前url
- hash
- search
- state
- match
- path
- url
- isExact
- params 动态路由传来的参数
但是用render时候,默认没有这些路由参数
需要自己传递。
render时候怎么传递路由参数呢?
👋手动把props传递下去
<Route path="/" exact render = {(props) => <HomePage {...props}/>} />
<Route path="/about" render = {(props) => <AboutPage {...props}/>} />
<Route render = {(props) => <NotFoundPage {...props}/>} />
withRouter 组件(高阶组件:传入一个组件,返回一个包装后的新组件)
如果一个组件不是路由绑定组件,那么该组件的props中是没有路由相关对象的,如果一层层传递参数,太过麻烦。可以使用withRouter来注入路由对象
import React from 'react'
import {withRoute} from 'react-router-dom'
function Child(props) {
console.log(props) // 带有路由信息的对象
return (
<div>使用withRoute包装过的子组件</div>
)
}
export default withRoute(Child)
别的方法获取路由信息,react-router-dom 提供的 hooks, react5+才有
- useHistory 获取history对象
- useLocation 获取location对象
- useParams 获取动态路由参数
- useRouteMatch 获取match对象
import React from 'react'
import {useHistory, useLocation, useParams, useRouteMatch} from 'react-router-dom'
function Child(props) {
console.log(useHistory(), useLocation(), useParams(), useRouteMatch()) // 带有路由信息的对象
return (
<div>带有路由信息的子组件</div>
)
}
export default Child
动态路由
// - 配置路由
<Route path="/list/:page" render={() => <ListPage>}/>
// - 使用路由
<Link to="/list/1">第1页</Link>
<Link to="/list/1">第1页</Link>
// - 获取路由信息 ListPage.js
import {useParams} from 'react-router-dom'
funciton ListPage(props) {
console.log('params对象:', useParams()) // params对象: {page: "1"}
}
重定向
- eg: 首页重定向到列表第一页
import {Redirect} from 'react-router-dom'
<Route path="/" render={
() => {return <Redirect to="/list/1">}
}>
综合实例
如下图,实现顶部和底部切换导航时候路由和列表的数据变化更新
目录结构
- src
- components
- FooterNav.js
- Inner.js
- List.js
- Nav.js
- http
- index.js
- router
- nav.js
- router.js
- App.css
- App.js
- index.js
- router/nav.js 定义顶部导航
const nav_data = [
// attention: 开始我写成url: '/all/:page',
// 出现很怪异现象,每多点击一个导航,页面实际url在累加
{
url: '/all/1',
txt: '全部',
type: 'all',
exact: true
},
{
url: '/good/1',
txt: '精华',
type: 'good',
exact: true
},
{
url: '/share/1',
txt: '分享',
type: 'share',
exact: true
},
{
url: '/ask/1',
txt: '问答',
type: 'ask',
exact: true
},
{
url: '/job/1',
txt: '招聘',
type: 'job',
exact: true
},
{
url: '/dev/1',
txt: '客户端测试',
type: 'dev',
exact: true
}
]
export default nav_data;
- router/router.js 定义路由信息
做了一些简单的页面重定向和404处理
import React from 'react'
import {Redirect} from 'react-router-dom'
import Inner from '../components/Inner'
const types = ['all', 'good', 'share', 'ask', 'job', 'dev']
const routes = [
{
path: '/',
exact: true,
render: ()=>{
return (<Redirect to="/all/1" />)
}
},
{
path: '/:type/:page',
exact: true,
render: (props) => {
const {pathname} = props.location;
const patharr = pathname.split('/')
if (types.includes(patharr[1]) && patharr[2] > 0) {
return <Inner/>
}
return (
<div>
404页面没找到
</div>
)
}
},
{
path: '/:type',
exact: true,
render: (props) => {
const {pathname} = props.location;
const patharr = pathname.split('/')
if (types.includes(patharr[1])) {
return <Redirect to={`/${patharr[1]}/1`}/>
}
return (
<div>
404页面没找到
</div>
)
}
},
{
path: '',
exact: false,
render() {
return (
<div>
404页面没找到
</div>
)
}
}
]
export default routes;
- App.js 使用定义好的导航,路由模块
import React from 'react';
import './App.css';
import Nav from './components/Nav'
import { Switch, Route } from 'react-router-dom';
import routes from './router/router'
function App() {
return (
<div className="App">
<Nav />
<Switch>
{
routes.map((item,index) => {
return <Route path={item.path} render={item.render} key={index} exact={item.exact} />
})
}
</Switch>
</div>
);
}
export default App;
- 组件components/Nav.js
import React from 'react'
import nav_data from '../router/nav'
import { NavLink } from 'react-router-dom'
export default function Nav() {
return (
<div>
{
nav_data.map((item, index) => {
return <NavLink className="link" to={item.url} key={index} exact={item.exact}>{item.txt}</NavLink>
})
}
</div>
)
}
- 组件components/Inner.js 中间列表和底部导航的页面,axios获取数据,传递给列表
import React, {useState, useEffect} from 'react'
import {useParams} from 'react-router-dom'
import List from './List'
import FooterNav from './FooterNav'
import getData from '../http/index'
export default function Inner() {
const {page, type} = useParams();
const [loading, setLoading] = useState(true)
const [data, setData] = useState([])
useEffect(() => {
// 加载数据
if (loading) {
getData(page, type).then(res => {
setData(res.data.data);
setLoading(false)
})
}
}, [loading])
useEffect(() => {
// 加载数据
setLoading(true)
}, [type, page])
return (
<div>
{
loading ? <p>加载中...</p> : <List data={data}/>
}
<FooterNav />
</div>
)
}
- 组件components/List.js
import React from 'react'
export default function List(props) {
const {data} = props;
return (
<ul>
{
data.map((item, index) => {
return <li key={item.id}>{item.title}</li>
})
}
</ul>
)
}
- 组件components/FooterNav.js
import React from 'react'
import {useParams, NavLink, useLocation, useRouteMatch, useHistory} from 'react-router-dom'
export default function FooterNav() {
const pages = [...('.').repeat(10)]
const {type }=useParams();
return (
<div className="footer-nav">
<ul>{
pages.map((item, index) => {
return <NavLink className="link" to={`/${type}/${index+1}`} key={index}>{index+1}</NavLink>
})
}</ul>
</div>
)
}
- http/index.js 获取数据的页面
import axios from 'axios'
const http = axios.create({
baseURL: 'https://cnodejs.org/api/v1'
})
function getData(page, type) {
return http.get(`/topics?page=${page}&tab=${type}&limit=10`)
}
export default getData;
- App.css
.App {
/* text-align: center; */
}
.link {
padding: 0 20px;
border-bottom: 1px solid gray;
}
.link.active {
border: 1px solid red;
border-bottom: 0;
color: red;
}
a {
text-decoration: none;
color: #333333;
}
.footer-nav ul {
overflow: hidden;
}
.footer-nav a{
width: 40px;
line-height: 20px;
text-align: center;
border: 1px solid gray;
float: left;
}
- index.js 项目入口
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import {BrowserRouter} from 'react-router-dom'
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
专栏系列快速链接
1-从零开始学react-认识react&jsx&props&state
2-从零开始学react-深入state,组件通讯,生命周期,受控组件
3-从零开始学react-其他api,初识hook
4-从零开始学react-hooks相关
5-从零开始学react - react-router-dom5
6-从零开始学react - redux相关
7-从零开始学react - 全家桶项目实战