react学习笔记3——基于React脚手架

React路由

相关理解

SPA的理解

  1. 单页Web应用(single page web applicationSPA)。
  2. 整个应用只有一个完整的页面
  3. 点击页面中的链接不会刷新页面,只会做页面的局部更新。
  4. 数据都需要通过ajax请求获取, 并在前端异步展现。

 路由的理解

  1. 什么是路由?
    1. 一个路由就是一个映射关系(key:value)
    2. key为路径, value可能是function或component
  2. 路由分类
    1. 后端路由:
      1. 理解: valuefunction, 用来处理客户端提交的请求。
      2. 注册路由: router.get(path, function(req, res))
      3. 工作过程:当node接收到一个请求时, 根据请求路径找到匹配的路由, 调用路由中的函数来处理请求, 返回响应数据
    2. 前端路由:
      1. 浏览器端路由,valuecomponent,用于展示页面内容。
      2. 注册路由: <Route path="/test" component={Test}>
      3. 工作过程:当浏览器的path变为/test, 当前路由组件就会变为Test组件

react-router-dom的理解

  1. react的一个插件库。
  2. 专门用来实现一个SPA应用。
  3. 基于react的项目基本都会用到此库。

react-router-dom相关API

内置组件

  1. <BrowserRouter>
  2. <HashRouter>
  3. <Route>
  4. <Redirect>
  5. <Link>
  6. <NavLink>
  7. <Switch>

其它 

  1. history对象
  2. match对象
  3. withRouter函数

基本路由使用

准备

  1. 下载react-router-dom: npm install --save react-router-dom
  2. 引入bootstrap.css: <link rel="stylesheet" href="/css/bootstrap.css">

路由的基本使用

index.js

//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <HashRouter>
    <App />
  </HashRouter>
);

App.jsx

import React, { Component } from "react";
import { Link, Route } from "react-router-dom";
import Home from "./components/Home";
import About from "./components/About";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <div className="page-header">
              <h2>React Router Demo</h2>
            </div>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件 */}
              <Link className="list-group-item" to="/about">
                About
              </Link>
              <Link className="list-group-item" to="/home">
                Home
              </Link>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About} />
                <Route path="/home" component={Home} />
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 About/index.jsx

import React, { Component } from 'react'

export default class index extends Component {
  render() {
    return (
      <h3>我是About的内容</h3>
    )
  }
}

Home/index.jsx

import React, { Component } from 'react'

export default class index extends Component {
  render() {
    return (
      <h3>我是Home的内容</h3>
    )
  }
}

 NavLink的使用

index.js

//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

 App.jsx

import React, { Component } from "react";
import { NavLink, Route } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件 */}
              <NavLink activeClassName="atguigu" className="list-group-item" to="/about">
                About
              </NavLink>
              <NavLink activeClassName="atguigu" className="list-group-item" to="/home">
                Home
              </NavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About} />
                <Route path="/home" component={Home} />
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 About/index.jsx

import React, { Component } from 'react'

export default class index extends Component {
  render() {
    // console.log('About组件收到的props是',this.props);
    return (
      <h3>我是About的内容</h3>
    )
  }
}

Home/index.jsx

import React, { Component } from 'react'

export default class index extends Component {
  render() {
    return (
      <h3>我是Home的内容</h3>
    )
  }
}

 封装NavLink

同上部分文件index.js,about,home

App.jsx

import React, { Component } from "react";
import { Route } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              {/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} />
              <MyNavLink to="/home" title="Home"/> */}
              {/* 把标签名作为标签体放在标签里面 */}
              {/* 标签属性,标签体内容 */}
              {/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink> */}
              {/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}
              {/* <NavLink to="/about" children="About"/> */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Route path="/about" component={About} />
                <Route path="/home" component={Home} />
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 components/MyNavLin/index.jsx

import React, { Component } from "react";
import { NavLink } from "react-router-dom";
export default class MyNavLink extends Component {
  render() {
    // props也可以拿到标签体内容
    console.log(this.props);
    // const {to,title} = this.props
    return (
      // {...this.props} 这样写将封装的NavLink标签里面的所有属性都带过来了,包括原本可以写在标签体中的children属性
      <NavLink activeClassName="atguigu" className="list-group-item" {...this.props} />
    );
  }
}

components/Header/index.jsx

import React, { Component } from 'react'

export default class Header extends Component {
  render() {
    // console.log('Header组件收到的props是',this.props);
    return (
      <div className="page-header">
        <h2>React Router Demo</h2>
      </div>
    )
  }
}

Switch的使用

App.jsx

import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
import Test from './pages/Test'
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              {/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} />
              <MyNavLink to="/home" title="Home"/> */}
              {/* 把标签名作为标签体放在标签里面 */}
              {/* 标签属性,标签体内容 */}
              {/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink> */}
              {/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}
              {/* <NavLink to="/about" children="About"/> */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                {/* 正常情况下 ,应该是path匹配上一个组件之后就不在继续往下匹配了,而目前的情况是path匹配上一个组件之后还会继续往下匹配,将所有匹配上的内容都展示在同一个path中 */}
                {/* 最好是让path匹配上一个之后就不继续往下问了,否则的话,继续往下面匹配,当组件特别多的时候,效率就会特别低 */}
                {/* 提高效率的方式,使用Switch,匹配上一个就不继续往下匹配了,可以改变顺序测试一下,谁在上面就先显示谁 */}
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  <Route path="/home" component={Test} />
                </Switch>
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 pages/Test/index.jsx

import React, { Component } from 'react'

export default class Test extends Component {
  render() {
    return (
      <div>
        <h2>Test...</h2>
      </div>
    )
  }
}

 解决样式丢失问题

index.js

//引入react核心库
import React from "react";
//引入ReactDOM
import ReactDOM from "react-dom/client";
//
import { BrowserRouter, HashRouter } from "react-router-dom";
//引入App
import App from "./App";

// 解决样式丢失问题三
//改变路由模式 #后面都是hash值,向3000请求数据的时候就不会带#后面的东西
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

App.jsx

import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              {/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} />
              <MyNavLink to="/home" title="Home"/> */}
              {/* 把标签名作为标签体放在标签里面 */}
              {/* 标签属性,标签体内容 */}
              {/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink> */}
              {/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}
              {/* <NavLink to="/about" children="About"/> */}
              <MyNavLink to="/atguigu/about">About</MyNavLink>
              <MyNavLink to="/atguigu/home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/atguigu/about" component={About} />
                  <Route path="/atguigu/home" component={Home} />
                </Switch>
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

public/index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <!-- ./以当前文件出发,去当前文件去找,这样写的话,在多级路径的情况下,就会把atguigu也带上了,在访问的时候 -->
    <!-- <link rel="stylesheet" href="./css/bootstrap.css" /> -->
    <!-- /表示的是直接去localhost:3000下面去请求东西,3000/css/bootstrap -->
    <!-- 解决样式丢失问题一 -->
    <!-- <link rel="stylesheet" href="/css/bootstrap.css" /> -->
    <!-- %PUBLIC_URL%代表的是public这个下面的绝对路径 -->
    <!-- 解决样式丢失问题二 -->
    <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css" />
    <style>
      /* 刚开始点击路由组件高亮的显示并不正常,原因是bootstrap的权限比较高,需要需要加上!important增加权限 */
      .atguigu {
        background-color: orange !important;
        color: white !important;
      }
    </style>
  </head>
  <body>
    <div id="root"></div>
  </body>
</html>

精准匹配与模糊匹配

App.jsx

import React, { Component } from "react";
import { Route,Switch } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header/>
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 原生html中,靠<a>跳转到不同的页面 */}
              {/* <a className="list-group-item" href="./about.html">About</a>
              <a className="list-group-item active" href="./home.html">Home</a> */}
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              {/* <MyNavLink to="/about" title="About" a={1} b={2} c={3} />
              <MyNavLink to="/home" title="Home"/> */}
              {/* 把标签名作为标签体放在标签里面 */}
              {/* 标签属性,标签体内容 */}
              {/* <MyNavLink to="/about" a={1} b={2} c={3}>About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink> */}
              {/* 可以把标签体的内容配在children属性中,也就不需要写开始标签与结束标签,直接自闭合就可以了 */}
              {/* <NavLink to="/about" children="About"/> */}
              <MyNavLink to="/about">About</MyNavLink>
              {/* 给多了,但是没要那么多,就是模糊匹配 */}
              {/* <MyNavLink to="/home/a/b">Home</MyNavLink> */}
              {/* 精准匹配,多给少给都匹配不上 */}
              <MyNavLink to="/home">Home</MyNavLink>
              {/* 这样匹配不上 */}
              {/* <MyNavLink to="/a/home/b">Home</MyNavLink> */}
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  {/* 精准匹配,多给少给都匹配不上,exact默认true */}
                  <Route exact={true} path="/about" component={About} />
                  <Route exact path="/home" component={Home} />
                  {/* 不匹配 */}
                  {/* 给少了,匹配的地方更多,就会匹配不上 */}
                  {/* <Route path="/home/a/b" component={Home} /> */}
                </Switch>
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 Redirect的使用

刚进网页页面的时候什么都没有选中

App.jsx

import React, { Component } from "react";
import { Route, Switch,Redirect } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/Header/MyNavLink";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  {/* 一般放在所有路由注册的最下方,当所有路由都无法匹配的时,跳转到Redirect指定的路由 */}
                  <Redirect to="/about" />
                </Switch>
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

嵌套路由使用

嵌套路由的使用

App.jsx

import React, { Component } from "react";
import { Route, Switch,Redirect } from "react-router-dom";
import Home from "./pages/Home";  //Home是路由组件
import About from "./pages/About"; //About是路由组件
import Header from "./components/Header"; //Header是一般组件
import MyNavLink from "./components/MyNavLink";
export default class App extends Component {
  render() {
    return (
      <div>
        <div className="row">
          <div className="col-xs-offset-2 col-xs-8">
            <Header />
          </div>
        </div>
        {/* <BrowserRouter> */}
        <div className="row">
          <div className="col-xs-2 col-xs-offset-2">
            <div className="list-group">
              {/* 在React中靠路由链接实现切换组件————编写路由链接 */}
              <MyNavLink to="/about">About</MyNavLink>
              <MyNavLink to="/home">Home</MyNavLink>
            </div>
          </div>
          <div className="col-xs-6">
            <div className="panel">
              <div className="panel-body">
                {/* 注册路由 */}
                <Switch>
                  <Route path="/about" component={About} />
                  <Route path="/home" component={Home} />
                  {/* 会导致无法开启二级路由 */}
                  <Route exact path="/home" component={Home} />
                  {/* 一般放在所有路由注册的最下方,当所有路由都无法匹配的时,跳转到Redirect指定的路由 */}
                  <Redirect to="/about" />
                </Switch>
              </div>
            </div>
          </div>
        </div>
        {/* </BrowserRouter> */}
      </div>
    );
  }
}

 pages/Home/index.jsx

import React, { Component } from 'react'
//默认暴露,这样引入
import MyNavLink from '../../components/MyNavLink'
import { Route,Switch,Redirect } from 'react-router-dom'
import News from './News'
import Message from './Message'
export default class index extends Component {
  render() {
    return (
      <div>
        <h3>我是Home的内容</h3>
        <div>
          <ul className="nav nav-tabs">
            <li>
              {/* 由于模糊匹配,可以匹配成功 */}
              <MyNavLink to="/home/news">News</MyNavLink>
            </li>
            <li>
              <MyNavLink to="/home/message">Message</MyNavLink>
            </li>
          </ul>
          {/* 注册路由 */}
          {/* 如果路径是/home/news下的,就匹配News */}
          <Switch>
            <Route path="/home/news" component={News} />
            <Route path="/home/message" component={Message} />
            {/* 会导致无法开启二级路由 */}
            {/* <Route exact path="/home/message" component={Message} /> */}
            <Redirect to="/home/news" />
          </Switch>
        </div>
      </div>
    )
  }
}

pages/Home/Message/index.jsx

import React, { Component } from "react";

export default class Message extends Component {
  render() {
    return (
      <div>
        <ul>
          <li>
            <a href="/message1">message001</a>&nbsp;&nbsp;
          </li>
          <li>
            <a href="/message2">message002</a>&nbsp;&nbsp;
          </li>
          <li>
            <a href="/message/3">message003</a>&nbsp;&nbsp;
          </li>
        </ul>
      </div>
    );
  }
}

pages/Home/News/index.jsx 

import React, { Component } from 'react'

export default class News extends Component {
  render() {
    return (
      <ul>
        <li>news001</li>
        <li>news002</li>
        <li>news003</li>
      </ul>
    )
  }
}

多种路由跳转方式

向路由组件传递params参数

pages/Home/index.jsx

import React, { Component } from 'react'
//默认暴露,这样引入
import MyNavLink from '../../components/MyNavLink'
import { Route,Switch,Redirect } from 'react-router-dom'
import News from './News'
import Message from './Message'
export default class index extends Component {
  render() {
    return (
      <div>
        <h3>我是Home的内容</h3>
        <div>
          <ul className="nav nav-tabs">
            <li>
              {/* 由于模糊匹配,可以匹配成功 */}
              <MyNavLink to="/home/news">News</MyNavLink>
            </li>
            <li>
              <MyNavLink to="/home/message">Message</MyNavLink>
            </li>
          </ul>
          {/* 注册路由 */}
          {/* 如果路径是/home/news下的,就匹配News */}
          <Switch>
            <Route path="/home/news" component={News} />
            <Route path="/home/message" component={Message} />
            {/* 会导致无法开启二级路由 */}
            {/* <Route exact path="/home/message" component={Message} /> */}
            <Redirect to="/home/news" />
          </Switch>
        </div>
      </div>
    )
  }
}

pages/Home/Message/index.jsx

import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
  state = {
    messageArr: [
      { id: '01', title: '消息1' },
      { id: '02', title: '消息2' },
      { id: '03', title: '消息3' }
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}
                  {/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}
                  {/* 向路由组件传递params参数 */}
                  <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr />
        {/* 声明接受params参数,前面是path值,后面是传递的id */}
        <Route path="/home/message/detail/:id/:title" component={Detail} />
      </div>
    );
  }
}

pages/Home/Message/Detail/index.jsx

import React, { Component } from 'react'
// 在子组件接收需要暂时的参数
const DetailData = [
  {id:'01',content: '你好,中国'},
  {id:'02',content: '你好,尚硅谷'},
  {id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {
  render() {
    const {id,title} = this.props.match.params
    const findResult = DetailData.find((detailObj)=>{
      return detailObj.id === id
    })
    return (
      <ul>
        <li>ID: {id}</li>
        <li>TITLE: {title}</li>
        <li>CONTENT: {findResult.content}</li>
      </ul>
    )
  }
}

向路由组件传递search参数

pages/Home/Message/index.jsx

import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
  state = {
    messageArr: [
      { id: '01', title: '消息1' },
      { id: '02', title: '消息2' },
      { id: '03', title: '消息3' }
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}
                  {/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp; */}
                  {/* 向路由组件传递search参数 */}
                  <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr />
        {/* 声明接受params参数,前面是path值,后面是传递的id */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
        {/* search参数无需声明接收、正常注册路由即可 */}
        <Route path="/home/message/detail" component={Detail} />
      </div>
    );
  }
}

pages/Home/Message/Detail/index.jsx

import React, { Component } from 'react'
import qs from 'querystring'
// let obj  ={name:'tom',age:18} //name=tom&age=18  key=value&key=value urlencoded的编码
// console.log(qs.stringify(obj)) //name=tom&age=18
// let str = 'carName=奔驰&price=199'
// console.log(qs.parse(str)); //{carName: '奔驰', price: '199'}
// 在子组件接收需要暂时的参数
const DetailData = [
  {id:'01',content: '你好,中国'},
  {id:'02',content: '你好,尚硅谷'},
  {id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {
  render() {
    console.log(this.props);
    //接受params参数
    // const {id,title} = this.props.match.params
    // 接收search参数
    const {search} = this.props.location
    const {id,title} = qs.parse(search.slice(1))
    const findResult = DetailData.find((detailObj)=>{
      return detailObj.id === id
    })
    return (
      <ul>
        <li>ID: {id}</li>
        <li>TITLE: {title}</li>
        <li>CONTENT: {findResult.content}</li>
      </ul>
    )
  }
}

向路由组件传递state参数

pages/Home/Message/index.jsx

import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
  state = {
    messageArr: [
      { id: '01', title: '消息1' },
      { id: '02', title: '消息2' },
      { id: '03', title: '消息3' }
    ]
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 传递数据刷新数据不会丢失 */}
                  {/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}
                  {/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp; */}
                  {/* 向路由组件传递search参数 */}
                  {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp; */}
                  {/* 向路由组件传递state参数 */}
                  {/* 这种方式传递数据刷新数据不会丢失 */}
                  <Link replace to={{pathname: '/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>&nbsp;&nbsp;
                </li>
              )
            })
          }
        </ul>
        <hr />
        {/* 声明接受params参数,前面是path值,后面是传递的id */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
        {/* search参数无需声明接收、正常注册路由即可 */}
        {/* <Route path="/home/message/detail" component={Detail} /> */}
        {/* state参数无需声明接收、正常注册路由即可 */}
        <Route path="/home/message/detail" component={Detail} />
      </div>
    );
  }
}

pages/Home/Message/Detail/index.jsx

import React, { Component } from 'react'
import qs from 'querystring'
// let obj  ={name:'tom',age:18} //name=tom&age=18  key=value&key=value urlencoded的编码
// console.log(qs.stringify(obj)) //name=tom&age=18
// let str = 'carName=奔驰&price=199'
// console.log(qs.parse(str)); //{carName: '奔驰', price: '199'}
// 在子组件接收需要暂时的参数
const DetailData = [
  {id:'01',content: '你好,中国'},
  {id:'02',content: '你好,尚硅谷'},
  {id:'03',content: '你好,未来的自己'},
]
export default class Detail extends Component {
  render() {
    console.log(this.props);
    //接受params参数
    // const {id,title} = this.props.match.params
    // 接收search参数
    // const {search} = this.props.location
    // const {id,title} = qs.parse(search.slice(1))
    //接收state参数
    const {id,title} = this.props.location.state || {}
    const findResult = DetailData.find((detailObj)=>{
      return detailObj.id === id
    }) || {}
    return (
      <ul>
        <li>ID: {id}</li>
        <li>TITLE: {title}</li>
        <li>CONTENT: {findResult.content}</li>
      </ul>
    )
  }
}

清除历史记录之后(在浏览器中清除)在访问这个网址就会报错了,Uncaught TypeError: Cannot destructure property 'id' of 'this.props.location.state' as it is undefined.   不能读取属性state从undefined中

 at Detail.render (index.jsx:22:1)

index.jsx:30Uncaught TypeError: Cannot read properties of undefined (reading 'content') at Detail.render (index.jsx:30:1) 不能读取属性findResult为undefined

使用 || {} 解决,这样就不会报错了

push与replace模式

 push与replace的不同

push相当于一种压栈的方式,不替换任何的路径,点击一个记录一个,留下痕迹

给所有路由链接加上replace之后,就不会加上任何记录

开启了replace之后,就是返回之后直接退回到News,而不是退回到message路径

编程式路由导航

pages/Home/News/index.jsx

import React, { Component } from 'react'

export default class News extends Component {
  // componentDidMount(){
  //   console.log('111');
  //   setTimeout(()=>{
  //     console.log('111');
  //     this.props.history.push('/home/message')
  //   }, 2000)
  // }
  render() {
    return (
      <ul>
        <li>news001</li>
        <li>news002</li>
        <li>news003</li>
      </ul>
    )
  }
}

pages/Home/Message/index.jsx

import React, { Component } from "react";
import {Link,Route} from 'react-router-dom'
import Detail from './Detail'
export default class Message extends Component {
  state = {
    messageArr: [
      { id: '01', title: '消息1' },
      { id: '02', title: '消息2' },
      { id: '03', title: '消息3' }
    ]
  }
  replaceShow = (id,title) =>{
    // replace跳转+携带params参数
    //编写一段代码,让其实现跳转到Detail组件,且为replace跳转、
    // this.props.history.replace(`/home/message/detail/${id}/${title}`)
    //replace跳转+携带search参数
    // this.props.history.replace(`/home/message/detail/?id=${id}&title=${title}`)
    //replace跳转+携带state参数
    this.props.history.replace('/home/message/detail',{id,title})
  }
  pushShow = (id,title) =>{
    //编写一段代码,让其实现跳转到Detail组件,且为push跳转、
    // push跳转+携带params参数
    // this.props.history.push(`/home/message/detail/${id}/${title}`)
    // push跳转+携带search参数
    // this.props.history.push(`/home/message/detail/?id=${id}&title=${title}`)
    //replace跳转+携带state参数
    this.props.history.push('/home/message/detail',{id,title})
  }
  back = () =>{
    this.props.history.goBack()
  }
  goForward = () =>{
    this.props.history.goForward()
  }
  go = () =>{
    this.props.history.go(-2)
  }
  render() {
    const { messageArr } = this.state
    return (
      <div>
        <ul>
          {
            messageArr.map((msgObj) => {
              return (
                <li key={msgObj.id}>
                  {/* 模板字符串是js里面的东西,所以要使用{``},模板字符串里面要混入,就写{} */}
                  {/* 这样写相当于模糊匹配,上面多,下面少,下面没有接收到 */}
                  {/* 向路由组件传递params参数 */}
                  {/* <Link to={`/home/message/detail/${msgObj.id}/${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp; */}
                  {/* 向路由组件传递search参数 */}
                  {/* <Link to={`/home/message/detail/?id=${msgObj.id}&title=${msgObj.title}`}>{msgObj.title}</Link>&nbsp;&nbsp; */}
                  {/* 向路由组件传递state参数 */}
                  {/* 这种方式传递数据刷新数据不会丢失 */}
                  <Link to={{pathname: '/home/message/detail',state:{id:msgObj.id,title:msgObj.title}}}>{msgObj.title}</Link>&nbsp;&nbsp;
                  <button onClick={()=>this.pushShow(msgObj.id,msgObj.title)}>push查看</button>
                  <button onClick={()=>this.replaceShow(msgObj.id,msgObj.title)}>replace查看</button>
                </li>
              )
            })
          }
        </ul>
        <hr />
        {/* 声明接受params参数,前面是path值,后面是传递的id */}
        {/* <Route path="/home/message/detail/:id/:title" component={Detail} /> */}
        {/* search参数无需声明接收、正常注册路由即可 */}
        {/* <Route path="/home/message/detail" component={Detail} /> */}
        {/* state参数无需声明接收、正常注册路由即可 */}
        <Route path="/home/message/detail" component={Detail} />
        <button onClick={this.back}>回退</button>&nbsp;
        <button onClick={this.goForward}>前进</button>&nbsp;
        <button onClick={this.go}>go</button>
      </div>
    );
  }
}

withRouter的使用

components/Header/index.jsx

import React, { Component } from 'react'
import {withRouter} from 'react-router-dom'
// withRouter解决在一般组件当中使用路由组件API
class Header extends Component {
  back = () =>{
    this.props.history.goBack() //history是undefined
  }
  forward = () =>{
    this.props.history.goForward()
  }
  go = () =>{
    this.props.history.go(-2)
  }
  render() {
    //如何让this.props拥有history
    console.log('Header组件收到的props是',this.props); //{}
    return (
      <div className="page-header">
        <h2>React Router Demo</h2>
        <button onClick={this.back}>回退</button>&nbsp;
        <button onClick={this.forward}>前进</button>&nbsp;
        <button onClick={this.go}>go</button>
      </div>
    )
  }
}
//暴露的是withRouter函数的返回值,作用:withRouter能够接收一个一般组件,然后就把这个一般组件的身上加上了路由组件所特有的那三个属性
export default withRouter(Header)
//withRouter可以加工一般组件,让一般组件具备路由组件所特有的API
// withRouter的返回值是一个新组件

测试代码:

<!DOCTYPE html>

<html lang="en">

  <head>

    <meta charset="UTF-8" />

    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Document</title>

  </head>

  <body>

    <!-- 若浏览器不支持js则展示标签中的内容 -->

    <noscript>抱歉!您的浏览器不支持js的运行</noscript>

    <div id="root"></div>

    <script>

      //1

      // let obj = { a: 1, b: 2 };

      // let obj2 = { ...obj, b: 3 };

      // console.log(obj2);

      //2

      // let obj = { a: 1, b: 2 };

      // delete obj.a;

      // console.log(obj);

      //3

      let obj = { a: { b: { c: 1 } } };

      let obj2 = { a: { b: 1 } };

      // console.log(obj.a.b.c);

      // const {

      //   a: {

      //     b: { c },

      //   },

      // } = obj;

      // console.log(c); //1

      const {

        a: { b: data },

      } = obj2;

      console.log(data);

    </script>

  </body>

</html>

额外注意:

按住alt键选中多个方法进行方法定义

安装包的时候最好只使用一种命令,npm i 或者yarn add

前端路由的——history:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>前端路由的基石_history</title>
</head>
<body>
	<a href="http://www.atguigu.com" onclick="return push('/test1') ">push test1</a><br><br>
	<button onClick="push('/test2')">push test2</button><br><br>
	<button onClick="replace('/test3')">replace test3</button><br><br>
	<button onClick="back()">&lt;= 回退</button>
	<button onClick="forword()">前进 =&gt;</button>

	<script type="text/javascript" src="https://cdn.bootcss.com/history/4.7.2/history.js"></script>
	<script type="text/javascript">
		// let history = History.createBrowserHistory() //方法一,直接使用H5推出的history身上的API
		let history = History.createHashHistory() //方法二,hash值(锚点)

		function push (path) {
			history.push(path)
			return false
		}

		function replace (path) {
			history.replace(path)
		}

		function back() {
			history.goBack()
		}

		function forword() {
			history.goForward()
		}

		history.listen((location) => {
			console.log('请求路由路径变化了', location)
		})
	</script>
</body>
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值