React笔记2——ReactAjax和React路由

React笔记2——ReactAjax和React路由

三、ReactAjax

1、脚手架配置

  1. 首先,安装一个轻量级框架axios

    yarn add axios
    
  2. 在App组件中定义两个简单的按钮分别用来获取学生数据和汽车数据。在测试时,需要打开测试服务器进行监听。

    import React, { Component } from 'react'
    import axios from 'axios'
    
    export default class App extends Component {
    	getStudentData = () => {
    		axios.get('http://localhost:3000/api1/students').then(
    			response => {console.log('成功了', response.data);},
    			error => {console.log('失败了', error);}
    		)
    	}
    
    	getCarData = () => {
    		axios.get('http://localhost:3000/api2/cars').then(
    			response => {console.log('成功了', response.data)},
    			error => {console.log('失败了', error);}
    		)
    	}
    
    	render() {
    		return (
    			
    ) } }
  3. 进行脚手架的配置,在src文件夹下创建setupProxy.js文件。因为配置文件一个项目只需要写一次,所以每次只需要把该文件进行复制粘贴即可。配置文件如下:(该项目因为向两个不同的服务器发送了请求,所以设置了两个代理)

    const proxy = require('http-proxy-middleware')
    
    module.exports = function(app) {
      app.use(
        proxy('/api1', { //遇见'/api1'前缀的请求,就会触发该代理配置
          target: 'http://localhost:5000', //请求转发给谁
          changeOrigin: true, //控制服务器收到的响应头中Host字段的值(这条写不写影响不大)
          pathRewrite: {'^/api1':''} //重写请求路径(必须的,用于走代理时将'/api1'换成空字符串)
        }),
        proxy('/api2', {
          target: 'http://localhost:5001',
          changeOrigin: true,
          pathRewrite: {'^/api2':''}
        })
      )
    }
    
  4. 代理配置总结

  • 方法1:

    在package.json中追加如下配置

    "proxy":"http://localhost:5000"
    

    说明:

    1. 优点:配置简单,前端请求资源时可以不加任何前缀。
    2. 缺点:不能配置多个代理。
    3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)
  • 方法2:

    1. 第一步:创建代理配置文件

      在src下创建配置文件:src/setupProxy.js
      
    2. 编写setupProxy.js配置具体代理规则:

      const proxy = require('http-proxy-middleware')
      
      module.exports = function(app) {
        app.use(
          proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
            target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
            changeOrigin: true, //控制服务器接收到的请求头中host字段的值
            /*
            	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
            	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
            	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
            */
            pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
          }),
          proxy('/api2', { 
            target: 'http://localhost:5001',
            changeOrigin: true,
            pathRewrite: {'^/api2': ''}
          })
        )
      }
      

    说明:

    1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
    2. 缺点:配置繁琐,前端请求资源时必须加前缀。

2、github搜索案例

  1. 将静态页面拆成React的Search、Item、List组件

  2. 将公共的样式放在App.css中,单独的样式也拆到各自的index.css里(该案例样式较为简单,所以只有List组件中有样式)

  3. state都定义在App组件中方便进行修改;App组件中定义了一个修改state的方法updateAppState并将其传给了Search组件

    import React, { Component } from 'react'
    import Search from './components/Search'
    import List from './components/List'
    
    export default class App extends Component {
    	state = {    //初始化状态
    		users: [], //users初始值为数组
    		isFirst: true, //是否为第一次打开页面
    		isLoading: false, //标识是否处于加载中
    		err: '', //存储请求相关的错误信息
    	} 
    
    	updateAppState = (stateObj) => {
    		this.setState(stateObj)
    	}
    
    	render() {
    		return (
    			
    ) } }
  4. Search组件

    1. 导入axios框架用于向github接口发送get请求;

    2. 利用ref核心属性给Search实例对象添加keyWordElement属性,该属性对应着input标签。同时keyWordElement是一个对象,它有一个value属性,该属性对应着input标签中输入的文字。

    3. 我们将该value属性重新赋值为keyword,并通过axios将关键字作为参数发送出去

      import React, { Component } from 'react'
      import axios from 'axios'
      
      export default class Search extends Component {
        search = () => {
          // 获取用户的输入(连续解构赋值+重命名)
          const {keyWordElement: {value:keyword}} = this
          
          // 发送请求前通知App更新状态
          this.props.updateAppState({isFirst:false, isLoading:true})
      
          // 发送网络请求
          // 因为我们端口是3001,也从该端口发送请求,所以可以省略http://localhost:3001
          axios.get(`/api1/search/users?q=${keyword}`).then(
            response => {
              // 请求成功后通知APP更新状态
              this.props.updateAppState({isLoading:false, users:response.data.items})
              // console.log(response);
            },
            error => {
              // 请求失败后通知APP更新状态
              this.props.updateAppState({isLoading: false, err: error.message, users: []})
              // console.log('失败了', error);
            }
          )
        }
      
        render() {
          return (
            

      搜索Github用户

      this.keyWordElement = c} type="text" placeholder="输入关键字点击搜索"/> 
      ) } }
  5. List组件

    1. App组件通过展开运算符把state所有属性通过props传递给List组件

    2. List通过解构赋值拿到必要的属性

    3. jsx只能写js表达式,而不能写for/if/switch这类js语句。故条件判断这里使用三元运算符。重点:三元表达式可以进行连续判断,效果相当于if语句

    4. 利用map对users数组进行处理,每个元素单独返回,并通过props将所有user属性传给Item组件

      import React, { Component } from 'react'
      import './index.css'
      import Item from '../Item'
      
      
      export default class List extends Component {
        render() {
          const {isFirst, users, isLoading, err} = this.props
          return (
            
      { isFirst ?

      欢迎使用,输入关键字,随后点击搜索

      : isLoading ?

      加载中...

      : err ?

      {err}

      : users.map((user) => { return }) }
      ) } }
  6. Item组件

    1. 对我们需要的user属性进行解构赋值,包括头像链接、用户仓库链接和用户名

    2. 将属性通过{}放在需要显示数据的位置

      import React, { Component } from 'react'
      
      export default class Item extends Component {
        render() {
          const {avatar_url, html_url, login} = this.props
          return (
            
      avatar

      {login}

      ) } }
  7. 代理文件

    const proxy = require('http-proxy-middleware')
    
    module.exports = function(app) {
      app.use(
        proxy('/api1', { //遇见'/api1'前缀的请求,就会触发该代理配置
          target: 'http://localhost:5000', //请求转发给谁
          changeOrigin: true, //控制服务器收到的响应头中Host字段的值(这条写不写影响不大)
          pathRewrite: {'^/api1':''} //重写请求路径(必须的,用于走代理时将'/api1'换成空字符串)
        })
      )
    }
    
  8. 总结

    1. 设计状态时要考虑全面,例如带有网络请求的组件,要考虑请求失败怎么办。
    2. ES6小知识点:解构赋值+重命名
      let obj = {a:{b:1}}
      const {a} = obj; //传统解构赋值
      const {a:{b}} = obj; //连续解构赋值
      const {a:{b:value}} = obj; //连续解构赋值+重命名

3、消息订阅-发布机制

  1. 使用PubSub

    1. 安装pubsub-js

      yarn install pubsub-js
      
    2. 使用方法(https://github.com/mroderick/PubSubJS)

      1. import PubSub from ‘pubsub-js’ //引入
      2. PubSub.subscribe(‘delete’, function(data){ }); //订阅
      3. PubSub.publish(‘delete’, data) //发布消息
  2. PubSub简化了App组件,因为该方法可以实现兄弟组件间的通信

  3. 简化的App组件

    import React, { Component } from 'react'
    import Search from './components/Search'
    import List from './components/List'
    
    export default class App extends Component {
    	
    	render() {
    		return (
    			
    ) } }
  4. Search组件

    1. 导入PubSub工具库,导入axios框架

    2. 使用PubSub.publish()方法发布消息,更新兄弟组件List的state

      import React, { Component } from 'react'
      import PubSub from 'pubsub-js'
      import axios from 'axios'
      
      export default class Search extends Component {
      
      
        search = () => {
       
          // 获取用户的输入(连续解构赋值+重命名)
          const {keyWordElement: {value:keyword}} = this
          
          // 发送请求前通知List更新状态
      this.props.updateAppState({isFirst:false, isLoading:true})
          PubSub.publish('atguigu', {isFirst:false, isLoading:true})
      
          // 发送网络请求
          // 因为我们端口是3000,也从该端口发送请求,所以可以省略http://localhost:3000
          axios.get(`/api1/search/users?q=${keyword}`).then(
            response => {
              // 请求成功后通知List更新状态
            PubSub.publish('atguigu', {isLoading:false, users:response.data.items})
              
            },
            error => {
              // 请求失败后通知List更新状态
             PubSub.publish('atguigu', {isLoading: false, err: error.message, users: []})
            }
          )
        
        }
      
        render() {
          return (
            

      搜索Github用户

      this.keyWordElement = c} type="text" placeholder="输入关键字点击搜索"/> 
      ) } }
  5. List组件

    1. state状态放在List组件中

    2. 在componentDidMount钩子函数中使用PubSub.subscribe()方法接收消息

    3. 在componentWillUnmount钩子函数中取消订阅

      import React, { Component } from 'react'
      import PubSub from 'pubsub-js'
      import './index.css'
      import Item from '../Item'
      
      
      export default class List extends Component {
      
        state = {    //初始化状态
      		users: [], //users初始值为数组
      		isFirst: true, //是否为第一次打开页面
      		isLoading: false, //标识是否处于加载中
      		err: '', //存储请求相关的错误信息
        }
      
        componentDidMount() {
          this.token = PubSub.subscribe('atguigu', (_, stateObj) => {
            // console.log('List组件收到数据了', data);
            this.setState(stateObj)
          })
        }
      
        componentWillUnmount() {
          PubSub.unsubscribe(this.token)
        }
      
        render() {
          const {isFirst, users, isLoading, err} = this.state
          return (
            
      {/* jsx只能写js表达式,而不能写for/if/switch这类js语句。故条件判断这里使用三元运算符。三元表达式可以进行连续判断 */} { isFirst ?

      欢迎使用,输入关键字,随后点击搜索

      : isLoading ?

      加载中...

      : err ?

      {err}

      : users.map((user) => { return }) }
      ) } }
  6. Item组件

    Item组件还保持跟之前一样。

四、React路由

1.react-router-dom

  • react的一个插件库。

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

  • 基于react的项目基本都会用到此库。

  • 安装react-router-dom

    yarn add react-router-dom
    

2.路由的基本使用

  1. 明确好界面中的导航区、展示区

  2. 导航区的a标签改为Link标签

    Demo
    
  3. 展示区写Route标签进行路径的匹配

    
    
  4. 的最外侧包裹了一个或

3.一个简单的路由跳转实例

  1. App组件,导入Link和Route

    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 (
    			

    React Router Demo

    {/* 原生html中,靠跳转不同的页面 */} {/* About Home */} {/* 在React中靠路由链接实现切换组件 */} About Home
    {/* 注册路由 */}
    ) } }
  2. components中的Home和About组件

    1. Home组件

      import React, { Component } from 'react'
      
      export default class Home extends Component {
        render() {
          return (
            

      我是Home的内容

      ) } }
    2. About组件

      import React, { Component } from 'react'
      
      export default class About extends Component {
        render() {
          return (
            

      我是About的内容

      ) } }

4.路由组件与一般组件

		1.写法不同:
					一般组件:
					路由组件:
		2.存放位置不同:
					一般组件:components
					路由组件:pages
		3.接收到的props不同:
					一般组件:写组件标签时传递了什么,就能收到什么
					路由组件:接收到三个固定的属性
										history:
													go: ƒ go(n)
													goBack: ƒ goBack()
													goForward: ƒ goForward()
													push: ƒ push(path, state)
													replace: ƒ replace(path, state)
										location:
													pathname: "/about"
													search: ""
													state: undefined
										match:
													params: {}
													path: "/about"
													url: "/about"

5.NavLink的使用

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

  1. 将导入的Link改为NavLink

  2. 若不写activeClassName,则默认对点击的NavLink添加一个active的类。因为这里导入了bootstrap.css样式,里面本身自带有active的样式。

  3. 若要自定义样式,可在index.html文件中通过style定义样式

    
    
    	
    		
    		react脚手架
    		
    		
    		
    	
    	
    		
  4. App.jsx组件中的NavLink

    	Home
    							About
    
  5. 自定义MyNavLink标签

    1. 在components创建MyNavLink文件,在这里对NavLink进行一层封装

    2. App组件的属性皆可以通过props传送过来

      					{/* 在React中靠路由链接实现切换组件 */}
      							Home
      							About
      
    3. MyNavLink标签中的Home、About会作为children属性传送过来,故利用展开运算符,可以将所有属性以简便的方式赋值给NavLink中的属性,如下是MyNavLink组件

      import React, { Component } from 'react'
      import {NavLink} from 'react-router-dom'
      
      export default class MyNavLink extends Component {
      
        render() {
          // console.log(this.props);
      
          return (
            
          )
        }  
      }
      
      

6.Switch的使用

  1. switch的使用

    • 通常情况下,path和component是一一对应的关系。
    • Switch可以提高路由匹配效率(单一匹配)。
  2. 举例说明

    
    
    
    

    ​ 如上三个路由显示节点,但有两个路径相同的Route。此时若点击MyNavLink所对应的按钮则会将路径相同的两个Route均render到页面上。

    ​ 此时可以import {Route, Switch} from ‘react-router-dom’,使用Switch标签将Route标签进行包裹,则在匹配到第一个路径时便会停止进行搜索路径了。

  3. 使用Switch的优点

    • 可以提高代码的效率(因为不会重复匹配路径)

7.解决样式丢失问题

  1. 出现问题的原因

    • 想要实现在所有路径前加一个固定的前缀,如公司名atguigu。则会出现css样式丢失的问题。

      Home
      About
      
      .....其他代码......
      
      
      	
      	
      	
      
      
  2. 解决方案

    • 打开public文件夹下的index.html

    • 默认的bootstap.css样式导入的方法为,该方法的问题是在进行路由跳转时会在路径中加上/atguigu,则会导致css文件找不到

      
      
      
    • 解决方案为:修改默认路径

      1.public/index.html 中 引入样式时不写 ./ 写 / (常用)
      2.public/index.html 中 引入样式时不写 ./ 写 %PUBLIC_URL% (常用)
      3.使用HashRouter
      

8.路由的严格匹配与模糊匹配

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

  2. 开启严格匹配:在路由中加上exact={true}。也可以就简便写成exact。

    //常规写法
    
    //简便写法
    
    
  3. 严格匹配不要随便开启,需要再开**,有些时候开启会导致无法继续匹配二级路由**。

9.Redirect的使用

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

  2. 使用方法:

    import {Route, Switch, Redirect} from 'react-router-dom'
    
    
    	
    	
    	
    
    
    

10.嵌套路由

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

  2. 路由的匹配是按照注册路由的顺序进行的。

  3. 使用案例:在路由组件中再导入新的路由组件,这样的话Route的路径便要填写二级路径了。在home路由组件中编写了News和Message两个新路由组件:

    import React, { Component } from 'react'
    import {Route, Switch, Redirect} from 'react-router-dom'
    import MyNavLink from '../../components/MyNavLink'
    import Message from './Message'
    import News from './News'
    
    export default class Home extends Component {
      render() {
        return (
          

    Home组件内容

    • News
    • Message
    ) } }

11.向路由组件传递参数

  1. 传递params参数:

    • 基本使用:

      路由链接(携带参数):详情
      注册路由(声明接收):
      接收参数:this.props.match.params
      
    • 使用案例:

      1.在Home组件中定义Message和News组件

      ​ 下面是News组件:

      import React, { Component } from 'react'
      
      export default class News extends Component {
        render() {
          return (
            
      • news001
      • news002
      • news003
      ) } }

      ​ 下面是Message组件:定义了state,state中的数据是用来传递给子组件Detail的;利用map方法对数组中的每一个元素单独返回,并定义id属性和to对应的路径;同时将参数传递给子组件;因为要传递的参数是变量,所以使用``而不是’’

      import React, { Component } from 'react'
      import {Link,Route} from 'react-router-dom'
      import Detail from './Detail'
      
      export default class Message extends Component {
      
        state = {
          messageArr: [
            {id: '01', title: '消息1'},
            {id: '02', title: '消息2'},
            {id: '03', title: '消息3'},
          ]
        }
      
        render() {
          const {messageArr} = this.state
          return (
            
        { messageArr.map((msgObj) => { return (
      • {/* 向路由组件传递params参数 */} {msgObj.title}
      • ) }) }

      {/* 声明接收params参数 */}
      ) } }

      ​ 下面是Detail组件:定义了一个数组变量,用来作为显示信息;通过路径传递过来的参数信息可以通过this.props.match.params获取;使用find方法找出id相对应的数组元素;将找出的结果信息进行render,显示到页面上。

      import React, { Component } from 'react'
      
      const DetailData = [
        {id: '01', content: '你好,中国'},
        {id: '02', content: '你好,尚硅谷'},
        {id: '03', content: '你好,未来的自己'}
      ]
      
      
      export default class Detail extends Component {
        render() {
          const {id, title} = this.props.match.params
          const findResult = DetailData.find((detailObj) => {
            return detailObj.id === id
          })
          // console.log(this.props);
          return (
            
      • ID:{id}
      • TITLE:{title}
      • CONTENT:{findResult.content}
      ) } }
  2. 传递search参数

    • 基本使用:

      路由链接(携带参数):详情
      注册路由(无需声明,正常注册即可):
      接收参数:this.props.location.search
      备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
      
    • 使用案例:

      案例还是如上传递params参数的案例。区别点在于:

      1.携带参数和注册路由方式不同。

      2.传递到Detail组件的参数的获取位置不同。

      3.参数在this.props.location中并且是以字符串的形式存在的,如search: “?id=01&title=消息1”

      4.所以需要对字符串进行剪切,并借助querystring解析将其转换成对象

      ​ 携带参数:

       {/* 向路由组件传递params参数 */}
      {/* {msgObj.title} */}
      
       {/* 向路由组件传递search参数 */}
      {msgObj.title}
      

      ​ 注册路由:

      {/* 声明接收params参数 */}
      {/*  */}
      
       {/* search参数无需声明接收,正常注册路由即可 */}
      
      

      ​ Detail组件:

      import React, { Component } from 'react'
      import qs from 'querystring'
      
      
      const DetailData = [
        {id: '01', content: '你好,中国'},
        {id: '02', content: '你好,尚硅谷'},
        {id: '03', content: '你好,未来的自己'}
      ]
      
      
      export default class Detail extends Component {
        render() {
          // const {id, title} = this.props.match.params
          // console.log(this.props);
      
          // 接收params参数
          // const {id, title} = this.props.match.params
      
          // 接收search参数
          const {search} = this.props.location
          const {id, title} = qs.parse(search.slice(1))
      
          const findResult = DetailData.find((detailObj) => {
            return detailObj.id === id
          })
          // console.log(this.props);
          return (
            
      • ID:{id}
      • TITLE:{title}
      • CONTENT:{findResult.content}
      ) } }
  3. 传递state参数

    • 基本使用:

      路由链接(携带参数):详情
      注册路由(无需声明,正常注册即可):
      接收参数:this.props.location.state
      备注:刷新也可以保留住参数
      
    • 使用案例:

      案例还是如上传递params参数的案例。区别点在于:

      1.携带参数和注册路由方式不同。

      2.传递到Detail组件的参数的获取位置不同。

      3.参数存在this.props.location.state中

      ​ 携带参数:

      {msgObj.title}
      

      ​ 注册路由:

      {/* state参数无需声明接收,正常注册路由即可 */}
      
      

      ​ Detail组件:

      import React, { Component } from 'react'
      // import qs from 'querystring'
      
      
      const DetailData = [
        {id: '01', content: '你好,中国'},
        {id: '02', content: '你好,尚硅谷'},
        {id: '03', content: '你好,未来的自己'}
      ]
      
      
      export default class Detail extends Component {
        render() {
          // const {id, title} = this.props.match.params
          // 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 || {} //若state为空,则传递一个空属性。避免报错
      
      
          const findResult = DetailData.find((detailObj) => {
            return detailObj.id === id
          }) || {}
          // console.log(this.props);
          return (
            
      • ID:{id}
      • TITLE:{title}
      • CONTENT:{findResult.content}
      ) } }

12.push与replace模式

  • push模式

    push模式也就是一般的使用情况,程序的几次路由跳转会被压进栈中。所以点击后退时会依次返回之前的路由。

  • replace模式

    在Link标签中加入replace={true},该路由在点击后则不会留下痕迹。点击回退也不会回到该路由所处位置。(简便模式,直接写一个replace在标签中也行)

    {msgObj.title}
    

13.编程式路由导航

​ 我们可以通过使用this.props.history对象上的API对操作路由进行跳转、前进和后退操作。

  • 实例操作:

    在Message组件的消息后面添加两个button按钮;

    按钮绑定点击事件,点击事件通过绑定箭头函数传入两个参数;

    分别定义使用push和replace两种方式进行跳转的方法;

    在Route中定义前进、后退和go方法的按钮;

    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'},
        ]
      }
    
      pushShow = (id, title) => {
        //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})
    
    
      }
    
      replaceShow = (id, title) => {
        //replace跳转+携带params参数
        // 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})
    
      }
    
      back = () => {
        // console.log(this.props.history);
        this.props.history.goBack()
      }
    
      forward = () => {
        this.props.history.goForward()
      }
    
      go = () => {
        this.props.history.go(2)
      }
    
      render() {
        const {messageArr} = this.state
        return (
          
      { messageArr.map((msgObj) => { return (
    • {/* 向路由组件传递params参数 */} {/* {msgObj.title} */} {/* 向路由组件传递search参数 */} {/* {msgObj.title} */} {/* 向路由组件传递state参数 */} {msgObj.title}    
    • ) }) }

    {/* 声明接收params参数 */} {/* */} {/* search参数无需声明接收,正常注册路由即可 */} {/* */} {/* state参数无需声明接收,正常注册路由即可 */}
    ) } }

14.withRouter的使用

​ 相比与一般组件,路由组件可以接收到不同的props。

  • 一般组件:写组件标签时传递了什么,就能收到什么。
  • 路由组件:接收到三个固定的属性history、location、match。

​ 当我们想要一般组件也可以拥有和路由组件一样props时(这样便可以调用props中的方法了。)

实例操作:

  • 在Header组件中添加前进、回退两个API按钮

  • 导入withouRouter方法,并将调用withRouter方法后的Header组件导出

    import React, { Component } from 'react'
    import {withRouter} from 'react-router-dom'
    
    class Header extends Component {
    
      back = () => {
        this.props.history.goBack()
      }
    
      forward = () => {
        this.props.history.goForward()
      }
    
      render() {
    
        console.log(this.props);
        return (
          

    React Router Demo

    ) } } export default withRouter(Header) // withRouter可以加工一般组件,让一般组件具备路由组件所特有的API // withRouter的返回值是一个新组件

15.BrowserRouter与HashRouter的区别

  1. 底层原理不一样:
    • BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
    • HashRouter使用的是URL的哈希值。
  2. path表现形式不一样
    • BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
    • HashRouter的路径包含#,例如:localhost:3000/#/demo/test
  3. 刷新后对路由state参数的影响
    • BrowserRouter没有任何影响,因为state保存在history对象中。
    • HashRouter刷新后会导致路由state参数的丢失!!!
  4. 备注:HashRouter可以用于解决一些路径错误相关的问题。
    • 比如7中提到的样式丢失问题

五、React——AntDesign组件库的使用

​ AntDesign官网:https://ant.design/index-cn。可以在官网的“在create-react-app中使用”查看具体的使用步骤。

  1. 安装依赖:

    yarn add antd
    
  2. 引入样式:

    import 'antd/dist/antd.css'
    
  3. Ant Design样式的使用——按钮

    ​ 在App组件中添加按钮:

    import React, { Component } from 'react'
    import { Button} from 'antd';
    import 'antd/dist/antd.css'
    
    export default class App extends Component {
    	render() {
    		return (
    			
    ) } }
  4. Ant Design样式的使用——图标

    在App组件中添加图标:

    import React, { Component } from 'react'
    import { Button } from 'antd';
    import 'antd/dist/antd.css'
    import {WechatOutlined, WeiboOutlined, SearchOutlined} from '@ant-design/icons'
    
    
    export default class App extends Component {
    
    	render() {
    		return (
    			
    ) } }
  5. antd的高级配置:

    通过按需引入样式,我们就不需要将样式全部导入了,可以将import 'antd/dist/antd.css’这行代码进行注销。

    自定义主题:

    按照 配置主题 的要求,自定义主题需要用到类似 less-loader 提供的 less 变量覆盖功能。我们可以引入 craco-less 来帮助加载 less 样式和修改变量。

    首先把 src/App.css 文件修改为 src/App.less,然后修改样式引用为 less 文件。

    /* src/App.js */
    - import './App.css';
    + import './App.less';
    
    /* src/App.less */
    - @import '~antd/dist/antd.css';
    + @import '~antd/dist/antd.less';
    

    ​ 然后安装 craco-less 并修改 craco.config.js 文件如下。

    $ yarn add craco-less
    
    const CracoLessPlugin = require('craco-less');
    
    module.exports = {
      plugins: [
        {
          plugin: CracoLessPlugin,
          options: {
            lessLoaderOptions: {
              lessOptions: {
                modifyVars: { '@primary-color': '#1DA57A' },
                javascriptEnabled: true,
              },
            },
          },
        },
      ],
    };
    

    这里利用了 less-loader 的 modifyVars 来进行主题配置,变量和其他配置方式可以参考 配置主题 文档。修改后重启 yarn start,如果看到一个绿色的按钮就说明配置成功了

你可能感兴趣的:(react.js,node.js,javascript)