当前位置: 首页 > news >正文

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.propsreturn (// {...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.statereturn (<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.paramsconst 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.statereturn (<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.locationconst {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.statereturn (<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.statereturn (<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拥有historyconsole.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);//3let obj = { a: { b: { c: 1 } } };let obj2 = { a: { b: 1 } };// console.log(obj.a.b.c);// const {//   a: {//     b: { c },//   },// } = obj;// console.log(c); //1const {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身上的APIlet 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>

相关文章:

  • 数字智慧方案6166丨智慧医养结合大数据平台方案(50页PPT)(文末有下载方式)
  • yum源配置文件CentOS-Base.repo完整内容
  • Python数据分析课程实验-1
  • pycharm安装的插件怎么显示在右侧
  • 深入解析三大查找算法:线性查找、二分查找与哈希查找的原理与应用
  • windows安装conda
  • 数值求解Eikonal方程的方法及开源实现
  • GitHub 趋势日报 (2025年04月30日)
  • 2025年一加7pro刷twpr / magisk / kali nethunter教程+资源下载+避坑指南
  • Linux安装部署Postgresql数据库
  • LiteOS与SLE透传实战案例
  • 【基础算法】插值查找算法 - JAVA
  • Java 算法入门:从基础概念到实战示例
  • MySQL数据同步之Canal讲解
  • 【Hice入门】Hive性能优化:存储与计算优化深度解析
  • 【C++指南】vector(三):迭代器失效问题详解
  • 前端如何转后端
  • JGQ516Ⅱ数据采集湿法袋式除尘器实验装置
  • Python学习笔记(第二部分)
  • 华为eNSP:IS-IS认证
  • 乌副总理:乌美签署矿产协议
  • 世界黄金协会:一季度全球黄金投资需求同比增170%
  • “铁血防守”制造8年最快丢球,恐惧中的阿森纳什么也做不了
  • 解放日报:持续拿出排头兵姿态先行者担当
  • 船只深夜撞上海上风机后沉没1死1失踪,调查报告公布
  • 俄罗斯延长非法滞留外国人限期离境时间至9月