React 路由使用

一. 安装

yarn add react-router-dom

二. 常用组件

⏹Router组件:包裹整个应用,一个React应用只需要使用一次

  • 两种常用的Router: HashRouter和BrowserRouter
  • HashRouter: 使用URL的哈希值实现 (localhost:3000/#/first)
  • 推荐👍 BrowserRouter:使用H5的history API实现(localhost3000/first)

⏹Link组件:用于指定导航链接(a标签)

  • 最终Link会编译成a标签,而to属性会被编译成 a标签的href属性

⏹Route组件:指定路由展示组件相关信息

  • path属性:路由规则,这里需要跟Link组件里面to属性的值一致
  • component属性:展示的组件
  • Route写在哪,渲染出来的组件就在哪

三. 主路由使用

import React from "react";

// 导入路由组件
import { BrowserRouter, Redirect, Route } from 'react-router-dom'

function App() {
  return (
    // 要想使用路由,需要使用Router包裹根组件
    <BrowserRouter>
      <div className="App">
        {/* 
          路由重定向,当我们访问默认地址的时候,重定向到/home路由,显示Index组件
          render: 是一个函数prop,用于指定要渲染的内容
          Redirect组件用于实现路由重定向,to属性指定要跳转到的路由地址
          ⏹有Tabbar的组件需要放到Home组件中,在Home组件中使用子路由
          ⏹React默认是模糊匹配,如果我们不给默认路由添加 exact 精确匹配的话,当访问 /map 的时候, / 路径也会被匹配到
        */}
        <Route exact path="/" render={() => <Redirect to="/home" />}></Route>
        <Route path="/home" component={Home}></Route>

        {/* ⏹没有Tabbar的组件和Home组件平级 */}
        <Route path="/citylist" component={CityList}></Route>
        {/* 
          ❗❗只有被路由直接渲染的组件才能通过props获取到路由信息,例如Map组价
            Map中使用的其他非直接被路由渲染的组件无法直接从props中获取到路由信息
            必须要使用withRouter高阶组件才可以
        */}
        <Route path="/map" component={Map}></Route>

        {/* 
          房源详情的路由规则
          :id代表路由参数,代表不固定的参数
          HouseDetail组件中使用此路由参数(也就是房屋的id)来获取房屋的详情数据
        */}
        <Route path="/detail/:id" component={HouseDetail}></Route>
        {/* 登录组件的路由地址 */}
        <Route path="/login" component={Login}></Route>
        {/* 注册组件的路由地址 */}
        <Route path="/registe" component={Registe}></Route>
      </div>
    </BrowserRouter>
  );
}

export default App;

四.子路由

import React, { lazy } from 'react'
// 导入路由
import { Route } from 'react-router-dom'
// 导入 TabBar
import { TabBar } from 'antd-mobile'

// 导入组件自己的样式文件
import './index.css'

import Index from '../Index'

const News = lazy(() => import('../News'))
const HouseList = lazy(() => import('../HouseList'))
const Profile = lazy(() => import('../Profile'))

// TabBar 数据
const tabItems = [
  {
    title: '首页',
    icon: 'icon-ind',
    path: '/home'
  },
  {
    title: '找房',
    icon: 'icon-findHouse',
    path: '/home/list'
  },
  {
    title: '资讯',
    icon: 'icon-infom',
    path: '/home/news'
  },
  {
    title: '我的',
    icon: 'icon-my',
    path: '/home/profile'
  }
]

export default class Home extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      // 从地址栏中获取,页面初始化时默认选中的Tab菜单
      selectedTab: this.props.location.pathname,
      // 是否隐藏TabBar
      hidden: false,
      // 是否全屏
      fullScreen: false,
    };
  }

  /*
    在此钩子函数中,当路由地址发生变化(Home组件中的子路由被触发)的时候,就会执行
    路由信息是通过props传递给组件的,因此通过比较更新前后的两个props中的路由信息
    通过此钩子函数实现了路由被切换,组件没有被重新加载时也能实现菜单高亮的效果
  */ 
  componentDidUpdate(preprops) {
    /*
    	preprops中存储着前一次的路由信息
    	this.props中存储着本次的路由信息
		当更新前后的两个路由地址不同的时候,说明发生了路由切换,此时更改当前选中的Tab菜单
	*/ 
    if (preprops.location.pathname !== this.props.location.pathname) {
      this.setState(() => {
        return {
          selectedTab: this.props.location.pathname,
        }
      });
    }
  }

  // 渲染 TabBar.Item
  renderTabBarItem() {
    // 遍历tabItems数据,动态的创建选项卡
    return tabItems.map(item => (
      <TabBar.Item
        title={item.title}
        key={item.title}
        // 动态的创建图标
        icon={<i className={`iconfont ${item.icon}`} />}
        // 选中时的图标
        selectedIcon={<i className={`iconfont ${item.icon}`} />}
        // 当前路由地址和当前Tab相同的话,设置为选中状态
        selected={this.state.selectedTab === item.path}
        onPress={() => {
          // 当按压下按钮之后,将选中的Tab设置为当前
          this.setState({
            selectedTab: item.path
          })

          // 实现路由切换,跳转到相应的组件
          this.props.history.push(item.path)
        }}
      />
    ))
  }

  render() {
    return (
      <div className="home">

        {/* 渲染子路由 */}
        <Route path="/home/news" component={News} />
        {/* 
            exact: 精确匹配
            父级路由和子级路由是同一个路由地址,只有当路由地址为/home的时候,才会匹配到Index组件
            如果我们不添加exact的话,当访问/home/list的时候,由于url中含有/home,Index组件也会被加载出来
        */}
        <Route exact path="/home" component={Index} />
        <Route path="/home/list" component={HouseList} />
        <Route path="/home/profile" component={Profile} />

        {/* 动态的创建TabBar */}
        <TabBar 
          tintColor="#21b97a" 
          barTintColor="white"
          // 设置不渲染内容
          noRenderContent={true}
        >
          {/* 调用渲染的方法 */}
          {this.renderTabBarItem()}
        </TabBar>
      </div>
    )
  }
}

五. withRouter高阶组件

注意:
1.只有被路由直接渲染的组件才能通过props获取到路由信息,例如A组件被路由直接渲染,A组件的子组件B组件因为没有被路由直接渲染,无法通过props获取到路由信息
2.没有被路由直接渲染的组件必须被withRouter高阶组件包裹之后才能在组件内部通过props获取到路由信息

// 导入withRouter高阶组件
import { withRouter } from 'react-router-dom'

// 从组件的props中解构出history对象
function NavHeader({ history }) {

    // 利用react中的路由,返回上一个页面
    const defaultHandler = () => history.go(-1);

    return (
        <div>
            <a onClick={defaultHandler}></a>
        </div>
    )
}

/*
    使用withRouter高阶组件包裹NavHeader组件,使其拥有获得路由信息的功能
    withRouter(NavHeader)函数的返回值也是一个组件
*/ 
export default withRouter(NavHeader)

六. props.location.state

handleFavorite = ()  => {
	
  // 获取出路由相关的对象
  const { history, location } = this.props;
  
  const isLogin = '判断用户是否登录';

  if (!isLogin) {
    // 未登录
    return alert('提示', '登录后才能收藏房源,是否去登录?', [
      { text: '取消' },
      { 
        text: '去登录',
        // 点击登录按钮之后,跳转到登录页面
        onPress: () => {
          console.log(location);
          /*
          	{
			    "pathname": "/detail/5e867853-1faf-7c51",
			    "search": "",
			    "hash": "",
			    "key": "jh8uj6"
			}
		  */
		  // 我们在跳转到/login页面之前,将当前页面的location信息添加到路由中
		  // 这样就可以在Login组件中通过props.location.state获取到我们额外添加的信息
		  // 在Login组件中根据props.location.state是否存在来判断登录之后跳转到前一个页面还是我们指定的页面
          return history.push('/login', {from: location})
        }
      }
    ])
  }
}

七. props.match.params

我们在路由中进行了如下配置

// 当路由地址为 /detail/XXX 的时候,就会匹配到HouseDetail组件
<Route path="/detail/:id" component={HouseDetail}></Route>

// 这个时候在HouseDetail组件中就可以通过props.match.params获取到路由中指定的id
class HouseDetail extends Component {
	state = {}
	
	test = () => {
		const { match: { params }} = this.props;
		console.log(params.id);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值