小言_互联网的博客

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

430人阅读  评论(0)

基本用法

  • 安装依赖: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,页面会加载首页组件
  • 当地址为http://localhost:3000/about,页面会加载关于我们组件

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

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


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')
);

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')
);

声明式跳转

Link

  • Link组件用于取代<a>元素,生成一个链接,允许用户点击后跳转到另一个路由。
  • 算是<a>元素的React 版本,可以接收Router的状态
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')
);


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')
);


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')
);


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')
);


编程式导航

  • 实现 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')
);

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')
);

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')
);

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>
      {
   /* <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')
);


  • 使用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')
);



嵌套路由

  • 就是路由的里面再写路由
  • 嵌套路由时,需要带上上一级的路径
  • 有子路由的页面,不能使用 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')
);


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登录页面先登录

上一篇博客:路由介绍


转载:https://blog.csdn.net/qq_45677671/article/details/116168250
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场