yarn add react-router-dom
BrowserRouter
HashRouter
Route组件
path
匹配的路径,默认模糊匹配component
组件名render
渲染组件,和componet二者选择一个exact
精确匹配Link组件
NavLink 组件
Switch组件
综合使用
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>
)
}
组件内部默认props:
需要自己传递。
render时候怎么传递路由参数呢?
手动把props传递下去
<Route path="/" exact render = {(props) => <HomePage {...props}/>} />
<Route path="/about" render = {(props) => <AboutPage {...props}/>} />
<Route render = {(props) => <NotFoundPage {...props}/>} />
如果一个组件不是路由绑定组件,那么该组件的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)
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"}
}
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
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;
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;
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;
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>
)
}
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>
)
}
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>
)
}
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>
)
}
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 {
/* 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;
}
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')
);