React 路由详解【学路由?看这一篇就够了】

文章目录

    • 基本用法
    • path 属性
    • Histroy 属性
      • HashRouter
      • BrowserRouter
    • 声明式跳转
      • Link
      • NavLink
    • 路由组件
      • component
      • render
      • children
    • 编程式导航
      • push
      • go
    • 路由传参
      • match.params
      • location.search
      • location.state
    • switch及404页面处理
    • 嵌套路由
    • withRouter添加路由属性
    • 路由守卫

基本用法

  • 安装依赖:npm i -S react-router-dom

  • 使用时,路由器 Router 就是 React 的一个组件。

  • Router 组件本身只是一个容器,真正的路由要通过 Route 组件定义。

path 属性

Route组件的path属性用来指定路由的匹配规则。

import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route} from 'react-router-dom';

const Home = () => (<div>首页</div>)
const About = () => (<div>关于我们</div>)
const App = () => (
  <Router>
    <div>
      <Route path={
     "/main"} component={
     Home} />
      <Route path={
     "/about"} component={
     About} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
  • 当地址为http://localhost:3000/main,页面会加载首页组件
    React 路由详解【学路由?看这一篇就够了】_第1张图片
  • 当地址为http://localhost:3000/about,页面会加载关于我们组件

React 路由详解【学路由?看这一篇就够了】_第2张图片

如果不写,那么不管路径是否匹配,总是会加载所有组件。

<Router>
    <div>
      <Route  component={
     Home} />
      <Route  component={
     About} />
    </div>
</Router>

React 路由详解【学路由?看这一篇就够了】_第3张图片
React 路由详解【学路由?看这一篇就够了】_第4张图片

Histroy 属性

  • 用来监听浏览器地址栏的变化,并将URL解析成一个地址对象

HashRouter

  • 如果设为HashHistory,路由将通过URLhash部分(#)切换,URL的形式类似http://localhost:3000/#/
import React from 'react';
import ReactDOM from 'react-dom';
import {
      HashRouter as Router, Route} from 'react-router-dom';

const Home = () => (<div>首页</div>)
const App = () => (
  <Router>
    <div>
      <Route path={
     "/"} component={
     Home} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第5张图片

BrowserRouter

  • 如果设为BrowserHistory,浏览器的路由就不再通过Hash完成了,而显示正常的路径http://localhost:3000/about
import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route} from 'react-router-dom';

const Home = () => (<div>首页</div>)
const App = () => (
  <Router>
    <div>
      <Route path={
     "/"} component={
     Home} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第6张图片

声明式跳转

Link

import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route,Link} from 'react-router-dom';

const Home = () => (<div>首页</div>)
const About = () => (<div>关于我们</div>)
const App = () => (
  <Router>
    <div>
      <Link to={
     "/"} exact={
     true} >首页</Link>
      ---
      <Link to={
     "/about"} >关于我们</Link>
    </div>
    {
     /* exact={true}  只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      <Route path={
     "/about"} component={
     About} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第7张图片
React 路由详解【学路由?看这一篇就够了】_第8张图片

NavLink

  • Link用法一致,稍微有点区别
  • NavLink可以设置用户的选中样式,Link不可以
import {
      BrowserRouter as Router, Route,NavLink} from 'react-router-dom';
<Router>
   <div>
     <NavLink to={
     "/"} exact={
     true} >首页</Link>
     ---
     <NavLink to={
     "/about"} >关于我们</Link>
   </div>
</Router>

路由组件

  • Route 设置 路由对应的组件有 3 种形式:

component

import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页页面</div>)
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第9张图片
React 路由详解【学路由?看这一篇就够了】_第10张图片

render

import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页</div>)
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
      ---
      <NavLink to={
     "/render"}>render</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      <Route path="/render" render={
     () => <div>render页面</div>} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第11张图片
React 路由详解【学路由?看这一篇就够了】_第12张图片

children

  • children 比较特殊,每个页面都会匹配上
import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页页面</div>)
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
      ---
      <NavLink to={
     "/child"}>children</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      {
     /* children 比较特殊,每个页面都会匹配上 */}
      <Route path="/child" children={
     () => <div>children页面</div>} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第13张图片
React 路由详解【学路由?看这一篇就够了】_第14张图片

编程式导航

  • 实现 js 中的页面跳转

push

  • 不传参: this.props.history.push("/about");
  • 传 params: this.props.history.push("/about/888");
  • 传 search:props.history.push("/cart?username=lili&age=12");
  • 传 state:props.history.push("/login", { kemu: 'html5', time: '1zhou' });(第二个参数传的是state的值)

go

  • 表示回退或前进多少页, -1 表示上一页
  • this.props.history.go(-1);

路由传参

  • 路由传参有三种方式

match.params

import React from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页</div>)
const About = (props) => (
	<div>关于我们页面<br/>
		接收到的参数:{
     props.match.params.userid}
	</div>
)
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
      ---
      <NavLink to={
     "/about/666"}>关于我们</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      <Route path={
     "/about/:userid"} component={
     About} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第15张图片

location.search

import React,{
     Component} from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页</div>)
class Cart extends Component {
     
  render() {
     
    console.log(this.props);
    return (<div>购物车页面<br/>
          {
     /* URLSearchParams:解构?号后面的数据 */}
         用户ID{
     new URLSearchParams(this.props.location.search).get('id')}<br/>
         用户名:{
     new URLSearchParams(this.props.location.search).get('name')}
    </div>);
  }
}
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
      ---
      <NavLink to={
     {
      pathname: "/cart", search: "?id=123&name=lili" }}>购物车</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      <Route path={
     "/cart"} component={
     Cart} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第16张图片

location.state

import React,{
     Component} from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, NavLink } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页</div>)
class State extends Component {
     
  render() {
     
    console.log(this.props);
    return (<div>
      state页面<br/>
      接收到的参数:{
     this.props.location.state.username}
    </div>);
  }
}
const App = () => (
  <Router>
    <div>
      <NavLink to={
     "/"} exact={
     true} >首页</NavLink>
      ---
      <NavLink to={
     {
      pathname: "/state", state: {
      "username": "山海经" } }}>state</NavLink>
    </div>
    {
     /*   只完全匹配/ */}
    <div>
      <Route path={
     "/"} exact={
     true} component={
     Home} />
      <Route path={
     "/state"} component={
     State} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第17张图片

switch及404页面处理

  • 问题:一个路径匹配了多个页面?

  • Switch 特点:匹配到第一个之后九不再往下匹配了

  • 可以用于处理 404 页面

  • 404页面组件需要放在路由表的最后面

  • 不使用switch

import React, {
      Component } from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, Link} from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页页面</div>)
class Cart extends Component {
     
  render() {
     
    return (<div>购物车页面</div>);
  }
}
const App = () => (
  <Router>
    <div>
      <Link to={
     "/"} exact={
     true} >首页</Link>
      --
      <Link to={
     {
      pathname: "/cart" }}>购物车</Link>
    </div>
    {
     /*  exact={true}: 表示只完全匹配/ */}
    <div>
      {
     /*  */}
        <Route path={
     "/"} exact={
     true} component={
     Home} />
        <Route path={
     "/cart"} component={
     Cart} />
        <Route render={
     () => <div>404页面</div>} />
      {
     /*  */}
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第18张图片
React 路由详解【学路由?看这一篇就够了】_第19张图片

  • 使用switch
import React, {
      Component } from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, Link, Switch} from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页页面</div>)
class Cart extends Component {
     
  render() {
     
    return (<div>购物车页面</div>);
  }
}
const App = () => (
  <Router>
    <div>
      <Link to={
     "/"} exact={
     true} >首页</Link>
      --
      <Link to={
     {
      pathname: "/cart" }}>购物车</Link>
    </div>
    {
     /*  exact={true}: 表示只完全匹配/ */}
    <div>
      <Switch>
        <Route path={
     "/"} exact={
     true} component={
     Home} />
        <Route path={
     "/cart"} component={
     Cart} />
        <Route render={
     () => <div>404页面</div>} />
      </Switch>
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第20张图片
React 路由详解【学路由?看这一篇就够了】_第21张图片
React 路由详解【学路由?看这一篇就够了】_第22张图片

嵌套路由

  • 就是路由的里面再写路由
  • 嵌套路由时,需要带上上一级的路径
  • 有子路由的页面,不能使用 exact = {true}
import React, {
      Component } from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, Link } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 

//需求:center页面中有两个子页面
class Center extends Component {
     
  render() {
     
    return <div>用户中心页面<br/>
      <Link to="/center/child1">子页1</Link>
      ||
      <Link to="/center/child2">子页2</Link>
      <div className="child">
        <Route path="/center/child1" component={
     Child1} />
        <Route path="/center/child2" component={
     Child2} />
      </div>
    </div>;
  }
}

const Child1 = () => (<div>子页 1 页面</div>)
const Child2 = () => (<div>子页 2 页面</div>)

const App = () => (
  <Router>
    <div>
      <Link to={
     "/center"} >用户中心</Link>
    </div>
    <div>
      <Route path={
     "/center"} component={
     Center} />
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

React 路由详解【学路由?看这一篇就够了】_第23张图片

React 路由详解【学路由?看这一篇就够了】_第24张图片
React 路由详解【学路由?看这一篇就够了】_第25张图片

withRouter添加路由属性

  • withRouter 可以给普通的组件添加路由属性
  • 一般用在头部,尾部,withRouter 用法是高阶组件
import React, {
      Component } from 'react';
import {
      withRouter } from 'react-router-dom';
import "./header.css"
class Header extends Component {
     
    constructor(props) {
     
        super(props);
        this.state = {
     }
    }

    goFenlei = () => {
     
        console.log(this);
        //Header 是一个组件,他不存在 路由中的history属性
        //可以使用 withRouter的高阶组件添加 history属性
        this.props.history.push("/about/23");
    }
    render() {
     
        return (
            <div className="header">头部
                <button onClick={
     this.goFenlei}>点击跳转到关于我们</button>
            </div>
        );
    }
}
export default withRouter(Header);

路由守卫

  • Redirect 重定向 ,可以做路由前置守卫
  • Prompt 路由后置守卫
import React, {
      Component } from 'react';
import ReactDOM from 'react-dom';
import {
      BrowserRouter as Router, Route, Link, Switch, Redirect, Prompt } from 'react-router-dom';
//BrowserRouter 不带#,NavLink有激活状态链接效果 
const Home = () => (<div>首页</div>)

class Center extends Component {
     
  render() {
     
    return (loginType ? <div>用户中心</div> : <Redirect to="/login" />);
  }
}

const Login = (props) => (<div>登录</div>)
class Cart extends Component {
     
  render() {
     
    console.log(this.props);
    return (<div>购物车页面

      <Prompt when={
     true} message={
     "您确定要离开这个页面么?"} />
    </div>);
  }
}
let loginType = false;
const App = () => (
  <Router>
    <div>
      <Link to={
     "/"} exact={
     true} >首页</Link>
      --
      <Link to={
     {
      pathname: "/cart" }}>购物车页面</Link>
      --
      <Link to={
     "/center"} >用户中心</Link>
      --
      <Link to={
     "/login"}  >登录</Link>
    </div>
    <div>
      <Switch>
        <Route path={
     "/"} exact={
     true} component={
     Home} />
        <Route path={
     "/cart"} component={
     Cart} />
        <Route path={
     "/center"} component={
     Center} />
        <Route path={
     "/login"} component={
     Login} />
        <Redirect from="/*" to="/" />
        {
     /* 404页面定位到首页 */}
      </Switch>
    </div>
  </Router>
)
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
上面代码实现的功能:
1. 给购物车页面设置了Prompt 路由后置守卫
2. 当你想离开购物车页面时,会弹出一个确认框
3.404页面设置了 Redirect 重定向
4. 当路径不对时,会重新定向到login登录页面
5. 给用户中心页面设置了Redirect 路由前置守卫
6. 当你为登录时,无法打开用户中心,只能跳转到login登录页面先登录

上一篇博客:路由介绍

你可能感兴趣的:(#,React,全套学习笔记,前端全套学习笔记,react,router,路由)