5-从零开始学react - react-router-dom5

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">}
}>

综合实例

如下图,实现顶部和底部切换导航时候路由和列表的数据变化更新
使用所有router相关知识实现一个简单的导航和分页
目录结构

	- src
		- components
			- FooterNav.js
			- Inner.js
			- List.js
			- Nav.js
		- http
			- index.js
		- router
			- nav.js
			- router.js
		- App.css
		- App.js
		- index.js
  1. 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;
  1. 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;
  1. 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;

  1. 组件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>
  )
}

  1. 组件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>
 )
}

  1. 组件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>
  )
}

  1. 组件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>
  )
}

  1. 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;
  1. 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;
}
  1. 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 - 全家桶项目实战

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值