React高级部分(一)

React应用(基于React脚手架)

使用create-react-app创建react应用

react脚手架

xxx脚手架:用来帮助程序员快速创建一个基于xxx库的模板项目

  • ① 包含了所有需要的配置(语法检查、jsx编译、devServer、……)。
  • ② 下载好了所有相关的依赖。
  • ③ 可以直接运行一个简单效果。

react提供了一个用于创建react项目的脚手架库:create-react-app

项目的整体技术架构为:react + webpack + es6 + eslint

使用脚手架开发项目的特点:模块化、组件化、工程化。

创建项目并启动

全局安装:

npm -g install create-react-app

切换到你想创建项目的目录:

create-react-app hello-react

进入项目文件夹:

cd hello-react

启动项目:

npm run start

react脚手架项目结构

public:静态资源文件夹。

  • favicon.icon:网站页签图标。
  • index.html:主页面。
  • logo192.png:logo图片。
  • logo521.png:logo图片。
  • manifest.json:应用加壳的配置文件。
  • robots.txt:爬虫协议文件。

src:源代码文件夹。

  • App.css:APP组件的样式。
  • App.js:APP组件。
  • App.text.js:用于给APP做测试。
  • index.css:样式。
  • index.js:入口文件。
  • logo.svg:logo图片。
  • reportWebVitals.js:页面性能分析文件(需要web-vitals库的支持)。
  • setupTests.js:组件单元测试的文件(需要jest-dom库的支持)。

功能界面的组件化编码流程(通用)

① 拆分组件:拆分界面,抽取组件。

② 实现静态组件:使用组件实现静态页面效果。

③ 实现动态组件:

  • 动态组件初始化数据。

    • 数据类型。
    • 数据名称。
    • 保存在哪个组件?
  • 交互(从绑定事件监听开始)。

组件化编码

项目结构

React高级部分(一)

创建组件

新建Hello组件

index.module.css

.title {
    background-color: orange;
}

index.jsx

import React, {Component} from "react";
import hello from './index.module.css'

export default class Hello extends Component {
    render() {
        return (
            <h2 className={hello.title}>Hello React(*^▽^*)</h2>
        );
    }
}

新建Welcome组件

index.module.css

.title {
    background-color: skyblue;
}

index.jsx

import React, {Component} from "react";
import welcome from './index.module.css'

export default class Welcome extends Component {
    render() {
        return (
            <h2 className={welcome.title}>Welcome</h2>
        );
    }
}

APP组件

App.jsx

import React, {Component} from "react";
import Hello from "./components/Hello"
import Welcome from "./components/Welcome"

//创建并暴露APP组件
export default class App extends Component {
    render() {
        return (
            <div>
                <Hello/>
                <Welcome/>
            </div>

        );
    }
}

index.js(入口文件)

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入APP组件
import App from './App';


ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
,
  document.getElementById('root')
);

其他文件

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <!-- %PUBLIC_URL%代表public文件夹的路径 -->
    <link href="%PUBLIC_URL%/favicon.ico" rel="icon"/>
    <!-- 用于开启理想视口,用于做移动端网页的适配 -->
    <meta content="width=device-width, initial-scale=1" name="viewport"/>
    <!-- 用于配置浏览器页签+地址栏的颜色(仅支持Android手机浏览器) -->
    <meta content="#000000" name="theme-color"/>
    <meta content="Web site created using create-react-app" name="description"/>
    <!-- 用于指定网页添加到手机主屏幕后的图标 -->
    <link href="%PUBLIC_URL%/logo192.png" rel="apple-touch-icon"/>
    <!-- 应用加壳的配置文件 -->
    <link href="%PUBLIC_URL%/manifest.json" rel="manifest"/>
    <title>React App</title>
</head>
<body>
    <!-- 如果浏览器不支持JS,则展示标签中的内容。 -->
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>
</html>

package.json

{
  "name""hello-react",
  "version""0.1.0",
  "private"true,
  "dependencies": {
    "@testing-library/jest-dom""^5.12.0",
    "@testing-library/react""^11.2.7",
    "@testing-library/user-event""^12.8.3",
    "react""^17.0.2",
    "react-dom""^17.0.2",
    "react-scripts""4.0.3",
    "web-vitals""^1.1.2"
  },
  "scripts": {
    "start""react-scripts start",
    "build""react-scripts build",
    "test""react-scripts test",
    "eject""react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

React ajax

前置说明

React本身只关注界面,并不包含发送ajax请求的代码。

前端应用需要通过ajax和后台进行交互(JSON数据)。

React应用中需要集成第三方ajax库(或自己封装)。

常用的ajax请求库

JQuery:比较重,如果需要另外引入,不建议使用。

axios:轻量级,建议使用。

  • 封装XMLHttpRequest对象的ajax。
  • Promise风格。
  • 可以用在浏览器端和node服务器端。

axios

官网

https://github.com/axios/axios。

安装

安装axios:

yarn add axios

axios的一些API

发送GET请求:

axios.get(url[,config]);

发送POST请求:

axios.post(url,data[,config]);

脚手架配置代理

方法1

假设客户端是http://localhost:3000,而服务器是http://localhost:5000。

浏览器有同源策略的限制,当我们的客户端和服务器只要协议、域名、端口一个不同,就不能接收到服务器传递的数据,脚手架中的package.json中配置代理(配置完重启一下,会开启一个代理服务器)。

React高级部分(一)

package.json:

{
  "name""react-ajax",
  "version""0.1.0",
  "private"true,
  "dependencies": {
    "@testing-library/jest-dom""^5.12.0",
    "@testing-library/react""^11.2.7",
    "@testing-library/user-event""^12.8.3",
    "axios""^0.21.1",
    "react""^17.0.2",
    "react-dom""^17.0.2",
    "react-scripts""4.0.3",
    "web-vitals""^1.1.2"
  },
  "scripts": {
    "start""react-scripts start",
    "build""react-scripts build",
    "test""react-scripts test",
    "eject""react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  },
  "proxy""http://localhost:5000"
}

发送请求的时候,将请求发送给http://localhost:3000,由代理给我们将请求发送给http://localhost:5000。

import React, {Component} from 'react';
import './APP.css'
import axios from "axios";

export default class App extends Component {

    //获取学生数据的回调
    getStudentData = () => {
        axios.get("http://localhost:3000/students")
            .then(response => {
                console.log('成功了', response.data);
            }, error => {
                console.log('失败了', error);
            })
    }

    render() {
        return (
            <div>
                <button onClick={this.getStudentData}>点我获取学生数据</button>
            </div>

        );
    }
}

注意:

此种方式是将public作为devServer的根路径,如果端口为3000的服务器没有数据,才将请求转发给5000端口的服务器,否则直接从3000端口的服务器获取。

这种方式太单一了,只能代理一个服务器。

方法2

在项目的src目录下新建一个名为setupProxy.js的文件,React脚手架会自动读取该文件,需要重启项目。

setupProxy.js的内容如下:

const proxy = require('http-proxy-middleware');

module.exports = function (app{
    app.use(
        //服务器代理
        proxy('/api1', { //遇见/api1前缀的请求,就会触发该代理配置
            target'http://localhost:5000',
            changeOrigintrue//控制服务器收到的请求头中Host字段的值
            //发送请求时,请求路径重写:将/api1/xxx --> xxx(去掉/api1)
            pathRewrite: {
                '^/api1'''
            }
        }),
        proxy('/api2', {
            target'http://localhost:5001',
            changeOrigintrue,
            //发送请求时,请求路径重写:将/api1/xxx --> xxx(去掉/api1)
            pathRewrite: {
                '^/api2'''
            }
        })
    )
}

消息订阅发布机制

概述

父子组件通过props进行通信。

兄弟组件通过pubsub(发布订阅)进行通信,当前也可以用于任意组件之间的通信。

5.2 使用

工具库:PubSubJS。

安装:

yarn add pubsub-js

使用:

import PubSub from 'pubsub-js'
PubSub.subscribe('消息名',(msg,data)=>{}); //订阅
PubSub.publish('消息名',{}); //发布消息

Fetch(扩展)

文档

https://github.github.io/fetch/

特点

fetch:原生函数,不再使用XMLHttpRequest对象提交Ajax请求。

老版本的浏览器可能不支持。

相关API

GET请求:

fetch(url).then(function(response{
    return response.json()
}).then(function(data{
    console.log(data)
}).catch(function(e{
    console.log(e)
});

POST请求:

fetch(url, {
    method"POST",
    bodyJSON.stringify(data),
}).then(function(data{
    console.log(data)
}).catch(function(e{
    console.log(e)
})

React路由

相关理解

SPA的理解

单页Web应用(Single Page Application,SPA)。

整个应用只有一个完整的页面。

点击页面中的链接不会刷新页面,只会做页面的局部更新。

数据都需要通过ajax请求获取,并在前端异步展现。

路由的理解

什么是路由?

一个路由就是一个映射关系(key:value)。

key为路径,value可能是function或component。

路由的分类

后端路由:

  • 理解:value是function,用来处理客户端提交的请求。
  • 注册路由:
router.get(path,function(req,resp)=>{})

工作过程:当Node接收到一个请求的时候,根据请求路径找到匹配的路由,调用路由中的函数来处理请求,返回响应数据。

前端路由:

  • 浏览器端路由,value是component,用于展示页面。
  • 注册路由:
<Route path="/test" component={Test}>

工作过程:当浏览器的path变为/test的时候,当前路由组件就变为Test组件。

react-router-dom的理解

React的一个插件库。

专门用来实现一个SPA应用。

基于React的项目基本上都会使用此库。

react-router-dom相关API

内置组件

  • <BrowserRouter>
  • <HashRouter>
  • <Route>
  • <Redirect>
  • <Link>
  • <NavLink>
  • <Switch>

其它

  • history对象
  • match对象。
  • withRouter函数。

路由的基本使用

准备工作

安装react-router-dom:

yarn add react-router-dom

在index.html页面中引入bootstrap.css

<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css" />

目录结构:

React高级部分(一)

使用步骤

① 明确好界面中的导航区、展示区。

② 导航区的a标签改为Link标签。

<Link to="/xxx">Demo</Link>

③ 展示区写Route标签进行路径的匹配。

<Route path="/xxx" component={Demo}/>

<APP/>的最外侧包裹了一个<BrowserRouter><HashRouter>

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

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>
                <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>
            </div>
        );
    }
}

components/Home/index.jsx

import React, {Component} from 'react';

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

components/About/index.jsx

import React, {Component} from 'react';

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

路由组件和一般组件

区别

① 写法不同:

  • 一般组件:
<Home/>
  • 路由组件:
<Route path="/home" component={Home}/>

② 存放的位置不同:

  • 一般组件:components。
  • 路由组件:pages。

③ 接收到的props不同:

  • 一般组件:写组件标签的时候传递了什么,就能接收到什么。
  • 路由组件:接收到三个固定的属性。
history:
    go: ƒ go(n)
    goBack: ƒ goBack()
    goForward: ƒ goForward()
    push: ƒ push(path, state)
    replace: ƒ replace(path, state)
location:
    pathname: "/about"
    search""
    stateundefined
match:
    params: {}
    path"/about"
    url"/about"

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {Link, 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>
                <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>
            </div>
        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

NavLink

概述

NavLink可以实现路由链接的高亮,通过activeClassName指定样式名。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {Route, NavLink} 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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" 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>
            </div>
        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

封装NavLink组件

概述

上面NavLink的案例中,如果路由链接越来越多的话,那么就会出现代码膨胀,后期维护也困难,我们将NavLink封装成组件,方便复用。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

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/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>
                <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" >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>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

components/MyNavLink/index.jsx

import React, {Component} from 'react';
import {NavLink} from 'react-router-dom';

export default class MyNavLink extends Component {
    render() {
        return (
            <NavLink className="list-group-item" activeClassName="active" {...this.props}/>
        );
    }
}

Switch

概述

通常情况下,path和component是一一对应的。

Switch可以提高路由匹配效率(单一匹配),只要匹配到了,就不会继续向下匹配。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

App.jsx

import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/Header";
import Test from "./pages/Test"//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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    <Route path="/home" component={Test}/>
                                </Switch>

                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

pages/Test/index.jsx

import React, {Component} from 'react';

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

        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

解决多级路径刷新页面样式丢失问题

概述

多级路径刷新页面样式丢失问题:

默认情况下,webpack 会将public目录作为根目录,假设devServer的的地址为http://localhost:3000,路由为/xudaxian/home,我们平常使用./等相对路径来书写样式路径。

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8"/>
    <!-- %PUBLIC_URL%代表public文件夹的路径 -->
    <link href="favicon.ico" rel="icon"/>
    <!-- 用于开启理想视口,用于做移动端网页的适配 -->
    <meta content="width=device-width, initial-scale=1" name="viewport"/>
    <title>解决样式丢失问题</title>
    <link href="./css/bootstrap.css" rel="stylesheet">
</head>
<body>
    <!-- 如果浏览器不支持JS,则展示标签中的内容。 -->
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
</body>
</html>

① 项目启动的时候,webpack会启动devServer,打开浏览器,并访问http://localhost:3000,其实webpack就会去public目录中寻找index.html,而bootstrap.css的路径设置的是./css/bootstrap.css,所以webpack会去public的目录中寻找css目录下是否有bootstrap.css,如果有,就返回此样式文件;如果没有,就返回index.html

② 此时,我们点击路由/xudaxian/home,因为不会刷新页面,所以样式不会丢失。

import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/xudaxian/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/xudaxian/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/xudaxian/about" component={About}/>
                                    <Route path="/xudaxian/home" component={Home}/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

③ 此时,我们刷新了浏览器,webpack会将/xudaxian也作为样式路径的一部分,即http://localhost:3000/xudaxian/css/bootstrap.css,但是public目录中是没有xudaxian目录的,更何况css/bootstrap.css文件,所以,因为找不到对应的样式文件,就返回index.html

解决方案:

  • ① pubilc/index.html中引入样式的时候,不写./,而写/(常用)。
  • ② pubilc/index.html中引入样式的时候,不写./,而写%PUBLIC_URL%(常用)。
  • ③ 使用HashRouter。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {HashRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <HashRouter>
            <App/>
        </HashRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/xudaxian/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/xudaxian/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/xudaxian/about" component={About}/>
                                    <Route path="/xudaxian/home" component={Home}/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

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

components/Header/index.jsx

import React, {Component} from 'react';

export default class Header extends Component {
    render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        );
    }
}

路由的模糊匹配和严格匹配

概述

默认使用的是模糊匹配(要求:【输入的路径】必须要包含【匹配的路径】,且顺序要一致)。

开启严格匹配:

<Route exact={true} path="/about" component={About}/>

严格匹配不要随便开启,需要再开,有些时候开启会导致无法继续匹配二级路由。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/a/b">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                </Switch>

                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

Redirect的使用

概述

一般写在路由注册的最下方,当所有路由都无法匹配的时候,跳转到Redirect指定的路由。

具体编码:

<Switch>
    <Route path="/about" component={About}/>
    <Route path="/home" component={Home}/>
    <Redirect to="/about"/>
</Switch>

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';

export default class Home extends Component {
    render() {
        console.log("Home",this.props);
        return (
            <h3>我是Home的内容</h3>
        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

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

嵌套路由

概述

注册子路由的时候要写上父路由的path值。

路由的匹配时按照注册路由的顺序进行的。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Route, Switch,Redirect} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        console.log("Home"this.props);
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route path="/home/message" component={Message}/>
                        <Redirect to="/home/news"/>
                    </Switch>
                </div>
            </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>

        );
    }
}

pages/Home/Message/index.jsx

import React, {Component} from 'react';

export default class Message extends Component {
    render() {
        return (
            <ul>
                <li>
                    message001&nbsp;&nbsp;
                </li>
                <li>
                    message002&nbsp;&nbsp;
                </li>
                <li>
                    message003&nbsp;&nbsp;
                </li>
            </ul>

        );
    }
}

component/Header/index.jsx

import React, {Component} from 'react';

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

向路由组件传递参数

向路由组件传递params参数

概述

路由链接(携带参数):

<Link to={"/demo/test/tom/18"}>详情</Link>

注册路由(声明接收):

<Route path="/demo/test/:name/:id" component={Detail}/>

接收参数:

this.props.match.params

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route path="/home/message" component={Message}/>
                        <Redirect to="/home/news"/>
                    </Switch>
                </div>
            </div>

        );
    }
}

pages/Homes/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>

        );
    }
}

pages/Homes/Message/index.jsx

import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";

export default class Message extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        {/* 向路由组件传递params参数 */}
                        <Link to={"/home/message/detail/1/message001"}>message001</Link>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/2/message002"}>message002</Link>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/3/message003"}>message003</Link>
                    </li>
                </ul>
                <hr/>
                <Switch>
                    {/* 声明接收params参数 */}
                    <Route path="/home/message/detail/:id/:title" component={Detail}/>
                </Switch>
            </div>

        );
    }
}

pages/Homes/Message/Detail/index.jsx

import React, {Component} from 'react';

export default class Detail extends Component {
    render() {
        //接收params参数
        const {id, title} = this.props.match.params;
        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:你好,中国。</li>
            </ul>

        );
    }
}

向路由组件传递search参数

概述

路由链接(携带参数):

<Link to={"/demo/test/?name=tom&age=18"}>详情</Link>

注册路由(无需声明,正常注册即可):

<Route path="/demo/test" component={Detail}/>

接收参数:

this.props.location.search

注意:

获取到的search是urlencoded编码的字符串,需要借助querystring解析。

React内部已经安装好了querystring。

使用:

import querystring from 'querystring';
querystring.parse();

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route path="/home/message" component={Message}/>
                        <Redirect to="/home/news"/>
                    </Switch>
                </div>
            </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>

        );
    }
}

pages/Home/Message/index.jsx

import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";

export default class Message extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        {/* 向路由组件传递search参数 */}
                        <Link to={"/home/message/detail/?id=1&title='message001'"}>message001</Link>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/?id=1&title='message002'"}>message002</Link>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/?id=1&title='message003'"}>message003</Link>
                    </li>
                </ul>
                <hr/>
                <Switch>
                    {/* 声明接收search参数,无需声明,正常注册即可 */}
                    <Route path="/home/message/detail/" component={Detail}/>
                </Switch>
            </div>

        );
    }
}

pages/Home/Message/Detail/index.jsx

import React, {Component} from 'react';
import qs from 'querystring';

export default class Detail extends Component {
    render() {
        const {search} = this.props.location;
        const {id,title} = qs.parse(search.slice(1));
        //接收params参数
        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:你好,中国。</li>
            </ul>

        );
    }
}

向路由组件传递state参数

概述

路由链接(携带参数):

<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>

注册路由(无需声明,正常注册即可):

<Route path="/demo/test" component={Detail}/>

接收参数:

this.props.location.state

注意:刷新也可以保留住参数。

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

export default class Header extends Component {
    render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        );
    }
}

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route path="/home/message" component={Message}/>
                        <Redirect to="/home/news"/>
                    </Switch>
                </div>
            </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>

        );
    }
}

pages/Home/Message/index.jsx

import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";

export default class Message extends Component {
    render() {
        return (
            <div>
                <ul>
                    <li>
                        {/* 向路由组件传递search参数 */}
                        <Link to={{pathname:'/home/message/detail',state:{id:1,title:'message001'}}}>message001</Link>
                    </li>
                    <li>
                        <Link to={{pathname:'/home/message/detail',state:{id:1,title:'message002'}}}>message002</Link>
                    </li>
                    <li>
                        <Link to={{pathname:'/home/message/detail',state:{id:1,title:'message003'}}}>message003</Link>
                    </li>
                </ul>
                <hr/>
                <Switch>
                    {/* 声明接收search参数,无需声明,正常注册即可 */}
                    <Route path="/home/message/detail/" component={Detail}/>
                </Switch>
            </div>

        );
    }
}

pages/Home/Message/Detail/index.jsx

import React, {Component} from 'react';

export default class Detail extends Component {
    render() {
        const {id,title} = this.props.location.state || {};
        //接收params参数
        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:你好,中国。</li>
            </ul>

        );
    }
}

components/Header/index.jsx

import React, {Component} from 'react';

export default class Header extends Component {
    render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        );
    }
}

总结路由参数

向路由组件传递params参数

路由链接(携带参数):

<Link to={"/demo/test/tom/18"}>详情</Link>

注册路由(声明接收):

<Route path="/demo/test/:name/:id" component={Detail}/>

接收参数:

this.props.match.params

向路由组件传递search参数

路由链接(携带参数):

<Link to={"/demo/test/?name=tom&age=18"}>详情</Link>

注册路由(无需声明,正常注册即可):

<Route path="/demo/test" component={Detail}/>

接收参数:

this.props.location.search

备注:获取到的search是urlencoded编码的字符串,需要借助querystring解析。

向路由组件传递state参数

路由链接(携带参数):

<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>

注册路由(无需声明,正常注册即可):

<Route path="/demo/test" component={Detail}/>

接收参数:

this.props.location.state

编程式路由导航

概述

借助 this.props.history 对象上的API操作路由跳转、前进、后退等。

this.props.history.push()
this.props.history.replace()
this.props.history.goBack()
this.props.history.goForward()
this.props.history.go()

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route path="/home/message" component={Message}/>
                        <Redirect to="/home/news"/>
                    </Switch>
                </div>
            </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>

        );
    }
}

pages/Home/Message/index.jsx

import React, {Component} from 'react';
import {Link, Route, Switch} from 'react-router-dom';
import Detail from "./Detail";

export default class Message extends Component {

    replaceShow = (id,title) => {
        //replace跳转+携带params参数
        this.props.history.replace(`/home/message/detail/${id}/${title}`);
    }

    pushShow = (id,title) => {
        //push跳转+携带params参数
        this.props.history.push(`/home/message/detail/${id}/${title}`);
    }

    forward = () => {
        this.props.history.goForward();
    }

    back = () => {
        this.props.history.goBack();
    }

    render() {
        return (
            <div>
                <ul>
                    <li>
                        {/* 向路由组件传递params参数 */}
                        <Link to={"/home/message/detail/1/message001"}>message001</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(1,'message001')}>push查看</button>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.replaceShow(1,'message001')}>replace查看</button>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/2/message002"}>message002</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(2,'message002')}>push查看</button>
                        &nbsp;&nbsp;
                        <button  onClick={()=>this.replaceShow(2,'message002')}>replace查看</button>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/3/message003"}>message003</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(3,'message003')}>push查看</button>
                        &nbsp;&nbsp;
                        <button  onClick={()=>this.replaceShow(3,'message003')}>replace查看</button>
                    </li>
                </ul>
                <hr/>
                <Switch>
                    {/* 声明接收params参数 */}
                    <Route path="/home/message/detail/:id/:title" component={Detail}/>
                </Switch>
                <button onClick={this.back}>后退</button>
                <button onClick={this.forward}>前进</button>
            </div>

        );
    }
}

pages/Home/Message/Detail/index.jsx

import React, {Component} from 'react';

export default class Detail extends Component {
    render() {
        //接收params参数
        const {id, title} = this.props.match.params;
        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:你好,中国。</li>
            </ul>

        );
    }
}

components/Header/index.js

import React, {Component} from 'react';

export default class Header extends Component {
    render() {
        return (
            <div className="page-header"><h2>React Router Demo</h2></div>
        );
    }
}

withRouter的使用

概述

withRouter函数让一般组件拥有路由组件的三个固定属性:

history:
    go: ƒ go(n)
    goBack: ƒ goBack()
    goForward: ƒ goForward()
    push: ƒ push(path, state)
    replace: ƒ replace(path, state)
location:
    pathname: "/about"
    search""
    stateundefined
match:
    params: {}
    path"/about"
    url"/about"

准备工作

目录结构:

React高级部分(一)

应用示例

示例:

index.js

//引入React核心库
import React from 'react';
//引入ReactDOm
import ReactDOM from 'react-dom';
//引入react-router-dom
import {BrowserRouter} from 'react-router-dom'
//引入APP组件
import App from "./APP";

ReactDOM.render(
    <React.StrictMode>
        <BrowserRouter>
            <App/>
        </BrowserRouter>
    </React.StrictMode>
,
    document.getElementById('root')
);

APP.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import Home from './pages/Home'//Home是路由组件
import About from "./pages/About"//About是路由组件
import Header from "./components/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>
                <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 className="list-group-item" activeClassName="active" to="/about">About</NavLink>
                            <NavLink className="list-group-item" activeClassName="active" to="/home">Home</NavLink>
                        </div>
                    </div>
                    <div className="col-xs-6">
                        <div className="panel">
                            <div className="panel-body">
                                {/* 注册路由 */}
                                {/* Switch可以提高路由匹配效率(单一匹配) */}
                                <Switch>
                                    <Route path="/about" component={About}/>
                                    <Route path="/home" component={Home}/>
                                    {/* 一般写在所有路由注册的最下方,当所有路由都无法匹配时,跳转到Redirect指定的路由。*/}
                                    <Redirect to="/about"/>
                                </Switch>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        );
    }
}

pages/About/index.jsx

import React, {Component} from 'react';

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

pages/Home/index.jsx

import React, {Component} from 'react';
import {NavLink, Redirect, Route, Switch} from 'react-router-dom';
import News from './News';
import Message from './Message';

export default class Home extends Component {
    render() {
        return (
            <div>
                <h3>我是Home的内容</h3>
                <div>
                    <ul className="nav nav-tabs">
                        <li>
                            <NavLink className="list-group-item" activeClassName="active" to="/home/news">News</NavLink>
                        </li>
                        <li>
                            <NavLink className="list-group-item" activeClassName="active"
                                     to="/home/message">
Message</NavLink>
                        </li>
                    </ul>
                    <Switch>
                        <Route path="/home/news" component={News}/>
                        <Route 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, Switch} from 'react-router-dom';
import Detail from "./Detail";

export default class Message extends Component {

    replaceShow = (id,title) => {
        //replace跳转+携带params参数
        this.props.history.replace(`/home/message/detail/${id}/${title}`);
    }

    pushShow = (id,title) => {
        //push跳转+携带params参数
        this.props.history.push(`/home/message/detail/${id}/${title}`);
    }

    forward = () => {
        this.props.history.goForward();
    }

    back = () => {
        this.props.history.goBack();
    }

    render() {
        return (
            <div>
                <ul>
                    <li>
                        {/* 向路由组件传递params参数 */}
                        <Link to={"/home/message/detail/1/message001"}>message001</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(1,'message001')}>push查看</button>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.replaceShow(1,'message001')}>replace查看</button>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/2/message002"}>message002</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(2,'message002')}>push查看</button>
                        &nbsp;&nbsp;
                        <button  onClick={()=>this.replaceShow(2,'message002')}>replace查看</button>
                    </li>
                    <li>
                        <Link to={"/home/message/detail/3/message003"}>message003</Link>
                        &nbsp;&nbsp;
                        <button onClick={()=>this.pushShow(3,'message003')}>push查看</button>
                        &nbsp;&nbsp;
                        <button  onClick={()=>this.replaceShow(3,'message003')}>replace查看</button>
                    </li>
                </ul>
                <hr/>
                <Switch>
                    {/* 声明接收params参数 */}
                    <Route path="/home/message/detail/:id/:title" component={Detail}/>
                </Switch>
                <button onClick={this.back}>后退</button>
                <button onClick={this.forward}>前进</button>
            </div>

        );
    }
}

pages/Home/Message/Detail/index.jsx

import React, {Component} from 'react';

export default class Detail extends Component {
    render() {
        //接收params参数
        const {id, title} = this.props.match.params;
        return (
            <ul>
                <li>ID:{id}</li>
                <li>TITLE:{title}</li>
                <li>CONTENT:你好,中国。</li>
            </ul>

        );
    }
}

pages/Home/News/index.jsx

import React, {Component} from 'react';

export default class News extends Component {

    // componentDidMount() {
    //     setTimeout(() => {
    //         this.props.history.push('/home/message');
    //     }, 2000)
    // }

    render() {
        return (
            <ul>
                <li>news001</li>
                <li>news002</li>
                <li>news003</li>
            </ul>

        );
    }
}

component/Header/index.jsx

import React, {Component} from 'react';
import {withRouter} from 'react-router-dom'

class Header extends Component {

    forward = () => {
        this.props.history.goForward();
    }

    back = () => {
        this.props.history.goBack();
    }

    render() {
        console.log(this.props);
        return (
            <div className="page-header">
                <h2>React Router Demo</h2>
                <button onClick={this.back}>后退</button>
                <button onClick={this.forward}>前进</button>
            </div>

        );
    }
}

export default withRouter(Header);

//withRouter可以加工一般组件,让一般组件具备路由组件特有的API。
//withRouter的返回值是一个新组件

BrowserRouter和HashRouter的区别

底层原理不一样

BrowserRouter使用的是H5的History API,不兼容IE9及以下版本。

HashRouter使用的是URL的哈希值。

path表现形式不一样

BrowserRouter的路径中没有#,例如:http://localhost:3000/demo/test

HashRouter的路径中包含#,例如:http://localhost:3000/#/demo/test

刷新后对路由state参数的影响

BrowserRouter没有任何影响,因为state保存在History对象之中。

HashRouter刷新后会导致路由state参数的丢失。

备注

HashRouter可以用于解决一些路径错误相关的问题。


原文始发于微信公众号(程序员阿晶):React高级部分(一)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/19895.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!