☀️学习系列:React中高级进阶必看属性

841 阅读35分钟

一、错误边界

1.何为错误边界?

React官网定义:错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。

简单来说就是在错误发生的时候,可以捕获到异常的代码并渲染备用的UI。有的人会说这不就是try{}catch(){}吗?其实我想说非也非也!try{}catch(){}很棒,但是try{}catch(){}仅仅只能用于命令式代码,而react组件是声明式。我们是用react-demo搭建我们的测试环境。然后git clone -> npm install -> npm run start,看见如下页面则表示成功。

接下来我们来修改一下代码:

class ErrorUI extends Component{

    state={
        mapArr:{}
    }

    render(){
        return(
            <ul>
                {
                    this.state.mapArr.map(item=><li>{"我是测试"}</li>)
                }
            </ul>
        )
    }
}

我们先是创建了一个组件,然后故意将mapArr设置为一个对象,在render返回时遍历,但其实对象并没有map属性,这时我们查看界面是一片空白,然后我们F12打开控制台会发现一片报红。但是明明是<ErrorUI />这个组件的问题,我们希望Hello React可以展示出来。

自 React 16 起,任何未被错误边界捕获的错误将会导致整个 React 组件树被卸载。即会产生空白现象。因为"显示错误的金额也比不呈现任何内容更糟糕"

那这怎么办呢?此时错误边界就派上用场了:

如果一个 class 组件中定义了 static getDerivedStateFromError()componentDidCatch()。 这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。前者渲染备用UI,后者打印错误信息。

class ErrorBoundary extends React.Component{
    constructor(props){
        super(props);
        this.state={hasError:false};
    }
    static getDerivedStateFromError(error) {
        //当出现错误时会进入这个生命周期函数
        // 更新 state 使下一次渲染能够显示降级后的 UI
        return { hasError: true };
    }
    componentDidCatch(error, errorInfo) {
        // 你同样可以将错误日志上报给服务器
        console.log(error);
        console.log(errorInfo);
    }
    render() {
        if (this.state.hasError) {
          // 你可以自定义降级后的 UI 并渲染
          return <h1>代码存在问题</h1>;
        }
    
        return this.props.children; 
    }

}
<div style={styleObj}>
                Hello React
                <ErrorBoundary>
                    <ErrorUI />
                </ErrorBoundary>
</div>

根据错误边界的定义,我们创建了一个错误边界组件,并将可能产生错误的组件包裹,然后再次打开浏览器。你会发现浏览器正确运行并且将错误UI替换成了你所写的备用UI。

虽然控制台有捕获到错误,但是这丝毫不影响页面中其他元素的错误。

2.错误边界的缺陷

  1. 事件处理(了解更多)
  2. 异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)
  3. 服务端渲染
  4. 它自身抛出来的错误(并非它的子组件)
  5. 语法错误

3.错误边界的实际用途

  1. 包裹在最顶层的路由组件并为用户展示一个 “Something went wrong” 的错误信息,就像服务端框架经常处理崩溃一样。
  2. 你也可以将单独的部件包装在错误边界以保护应用其他部分不崩溃。

二、Fragment标签

1.Fragment标签极其用途

假设有这样一个场景,一个父组件希望子组件仅有2个div标签,但是如下所写肯定是有问题的, 因为在React的render方法/Vue的template中必须有一个根元素节点。

class LiComponent extends React.Component{
    
    render(){
        return(
            <div>我是</div>
            <div>测试</div>
            <div>子元素</div>
        )
    }
}
<div style={styleObj}>
                Hello React
                <BoundErrorComponent>
                    <LiComponent />
                </BoundErrorComponent> 
</div>

这是我们需要将子元素用一个节点包裹起来,不然会产生语法错误,但是我们不想增加额外节点,从始至终都是这个节点该怎么做呢?使用<Fragment />标签进行包裹。

<Fragment>
                <div>我是</div>
                <div>测试</div>
                <div>子元素</div>
</Fragment>

打开浏览器即可发现

2.为什么在Reactrender方法/Vuetemplate中必须有一个根元素节点呢?

2.1.vue

当我们实例化Vue的时候,填写一个el选项,来指定我们的SPA入口:

let vm=new Vue({
    el:"#app"
})

同时我们也会在body里面新增一个id为app的div

<body>
    <div id="app"></div>
</body>

这很好理解,就是为vue开启一个入口,那我们不妨来想想,如果我在body下这样

<body>
<div id='app1'></div>
<div id='app2'></div>
</body

Vue其实并不知道哪一个才是我们的入口,因为对于一个入口来讲,这个入口就是一个‘Vue类',Vue需要把这个入口里面的所有东西拿来渲染,处理,最后再重新插入到dom中。如果同时设置了多个入口,那么vue就不知道哪一个才是这个‘类'。当我们在webpack搭建的vue开发环境下,使用单文件组件时,你可能会这样:

<template>
<div class='component'></div>
</template>

那这里为什么template下也必须有且只能有一个div呢? 这里我们要先看一看template这个标签,这个标签是HTML5出来的新标签,它有三个特性:

  1. 隐藏性:该标签不会显示在页面的任何地方,即便里面有多少内容,它永远都是隐藏的状态;
  2. 任意性:该标签可以写在页面的任何地方,甚至是head、body、sciprt标签内;
  3. 无效性:该标签里的任何HTML内容都是无效的,不会起任何作用;

但是呢,你可以通过innerHTML来获取到里面的内容。知道了这个,我们再来看.vue的单文件组件。其实本质上,一个单文件组件,本质上(我认为)会被各种各样的loader处理成为.js文件(因为当你import一个单文件组件并打印出来的时候,是一个vue实例),通过template的任意性我们知道,template包裹的HTML可以写在任何地方,那么对于一个.vue来讲,这个template里面的内容就是会被vue处理为虚拟dom并渲染的内容,导致结果又回到了开始 :既然一个.vue单文件组件是一个vue实例,那么这个实例的入口在哪里?

如果在template下有多个div,那么该如何指定这个vue实例的根入口?为了让组件能够正常的生成一个vue实例,那么这个div会被自然的处理成程序的入口。通过这个‘根节点',来递归遍历整个vue‘树'下的所有节点,并处理为vdom,最后再渲染成真正的HTML,插入在正确的位置。那么这个入口,就是这个树的‘根',各个子元素,子组件,就是这个树的‘枝叶',而自然而然地,这棵‘树',就是指一个vue实例了。

2.2 React

在阅读源码后我们发现render返回值类型为React.Node,而React.Node包含如上几种类型。

其实和Vue的道理一样,如果你不写一个根div,入口无法判别哪个才是真正的实例入口

2.3 总结

就像一个HTML文档只能有一个根元素一样.... 多个根元素必将导致无法构成一颗树。

3.带key<Fragment />

有可能你会遇到下面的某种情况

  state={
        arr:new Array(10).fill("测试")
    }
    render(){
        return(
            <div>
                {
                    this.state.arr.map((item,index)=>(
                        <Fragment>
                            <div>{`测试${index}`}</div>
                        </Fragment>
                    ))
                }
            </div>
        )
    }

但是你在控制台会看见这样的警告

原因:react的key关乎到react的dom-diff算法 react中对于dom的操作是根据生成的data-reactid进行绑定的,添加key可以保证dom结构的完整性,而不会根据react自己对dom标记的key进行重新分配 react每次决定重新渲染的时候,几乎完全是根据data-reactid来决定的。

细心的Fragment显然是注意到了这一点。

 <Fragment key={index}>
    <div>{`测试${index}`}</div>
 </Fragment>

Tips:key 是唯一可以传递给 Fragment 的属性。未来我们可能会添加对其他属性的支持,例如事件。

三、Context

1.何为Context

如上图,假设props为棒棒糖,爷爷想给孙子一块棒棒糖,在传统react中,想给孙子棒棒糖需要将棒棒糖给爸爸,然后爸爸再给儿子,实际的目的是给儿子,但是谁知道爸爸会不会偷吃呢?

Context应运而生,Context设计的目的就是为了解决这种问题,没有中间商赚差价。


//传统react写法
//顶层father组件
import React,{Fragment,Component}  from 'react';
import Father from './Father';
export default class GrandFather extends React.Component{

   state={
       some:"大白兔奶糖"
   }

   render(){
       return(
           <div >
               <div>{`全局共享数据:`}<span style={{color:"red"}}>{this.state.some}</span></div>

               {`爷爷给孙子一块`}<span style={{color:"red"}}>{this.state.some}</span>
               <Father some={this.state.some}/>
           </div>
       )
   }
}
//中间层父亲组件
import React,{Fragment,Component}  from 'react';
import Son from './Son';
export default class Father extends React.Component{
   render(){
       return(
           <div>
             
               {`父亲接収到爷爷给他的 `}<span style={{color:"red"}}>{this.props.some}</span>
               <Son some={this.props.some}/>
           </div>
       )
   }
}
//底层儿子组件
import React,{Fragment,Component}  from 'react';
export default class Son extends React.Component{

   render(){
   
       return(
           <div  >
               {`儿子接収到爷爷给他的 `}<span style={{color:"red"}}>{this.props.some}</span>
           </div>
       )
   }
}

查看效果

使用Context改造后
//爷爷组件
import React from 'react';
import Father from './Father';
export const SomeContext=React.createContext();
 
export default class GrandFather extends React.Component{

    state={
        some:"大白兔奶糖"
    }

    render(){
        return(
            <div >
                <div>{`全局共享数据:`}<span style={{color:"red"}}>{this.state.some}</span></div>

                {`爷爷给孙子一块`}<span style={{color:"red"}}>{this.state.some}</span>
                <SomeContext.Provider value={"大白兔奶糖"} >
                    <Father />
                </SomeContext.Provider>
            </div>
        )
    }
}
 
//父亲组件内容不变
//儿子组件
import React, { Fragment, Component } from 'react';
import { SomeContext } from './GrandFather'
export default class Son extends React.Component {

    render() {

        return (
            <SomeContext.Consumer>
                {value => {
                    return <div  >
                        {`儿子接収到爷爷给他的 `}<span style={{ color: "red" }}>{value}</span>
                    </div>
                }}
            </SomeContext.Consumer>
        )
    }
}

2.相关API介绍

  • React.createContext
const MyContext = React.createContext(defaultValue);

<MyContext.Consumer>
 {defaultValue=>/**/}
</MyContext.Consumer>
或者
const MyContext=React.createContext();
<MyContext.Provider value={"some"}>
    <Component />
<MyContext.Provider>
   
<MyContext.Consumer>
 {value=>/**/}
</MyContext.Consumer>

创建一个Context对象。当React渲染一个订阅(ProviderContext对象的组件。这个组件会从组件树中离自身最近的那个匹配的 Provider 中读取到当前的 context 值。换句话说,如果组件树中没有Provider时,defaultValue才会生效,否则无法生效。

  • Context.Provider

生产者,提供数据的API,其中,当Providervalue值发生变化时,它内部的所有消费组件都会重新渲染,且不受制于shouldComponentUpdate函数。

<MyContext.Provider value={"some"}>
    <Component />
<MyContext.Provider>
  • Class.contextType
import React from 'react';
import Father from './Father';
export const SomeContext=React.createContext("some");
 
export default class GrandFather extends React.Component{

    state={
        some:"大白兔奶糖"
    }

    static contextType = SomeContext;

    render(){a
        return(
            <div >
                <div>{`全局共享数据:`}<span style={{color:"red"}}>{this.context}</span></div>
            </div>
        )
    }
}

挂载在 class 上的 contextType 属性会被重赋值为一个由 React.createContext() 创建的 Context 对象。并可通过this.context获取value

  • Context.Consumer

消费者,包裹函数,这个函数接收当前的 context 值,返回一个 React 节点。传递给函数的 value 值等同于往上组件树离这个 context 最近的 Provider 提供的 value 值。如果没有对应的 Providervalue 参数等同于传递给 createContext()defaultValue

<MyContext.Consumer>
  {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>

3.高级用法

1.嵌套组件中更新context

传递一个函数,使得consumers组件更新context,即更新生产者的state

const ThemeContext = React.createContext({
  theme: themes.dark,
  toggleTheme: () => {},
});
<ThemeContext.Provider value={this.state}>
    <Content />
</ThemeContext.Provider>
<ThemeContext.Consumer>
      {({theme, toggleTheme}) => (
        <button
          onClick={toggleTheme}
          style={{backgroundColor: theme.background}}>

          Toggle Theme
        </button>
      )}
</ThemeContext.Consumer>

2.消费多个Context

//生产者
<ThemeContext.Provider value={theme}>
    <UserContext.Provider value={signedInUser}>
          <Layout />
    </UserContext.Provider>
</ThemeContext.Provider>
//消费者
<ThemeContext.Consumer>
      {theme => (
        <UserContext.Consumer>
          {user => (
            <ProfilePage user={user} theme={theme} />
          )}
        </UserContext.Consumer>
      )}
</ThemeContext.Consumer>

4.注意事项

当 provider 的父组件进行重渲染时,可能会在 consumers 组件中触发意外的渲染。举个例子,当每一次 Provider 重渲染时,以下的代码会重渲染所有下面的 consumers 组件,因为 value 属性总是被赋值为新的对象:

class App extends React.Component {
  render() {
    return (
      <Provider value={{something: 'something'}}>
        <Toolbar />
      </Provider>
    );
  }
}
//转化后
class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: {something: 'something'},
    };
  }

  render() {
    return (
      <Provider value={this.state.value}>
        <Toolbar />
      </Provider>
    );
  }
}

四、高阶组件(重点)

高阶组件是这篇文章的重点,合理运用好高阶组件,会让开发变得更加有效率,同时代码也会变得更优雅。

1.何为高阶组件

高阶组件是参数为组件,返回值为新组件的函数。高阶组件是一个函数,一个返回新组件的函数。

const EnhancedComponent = higherOrderComponent(WrappedComponent);

2.何时应该使用高阶组件

当你的组件里面有大量的重复的代码,这些代码仅有一些参数之类的变化,这时你就可以使用高阶函数,将共用部分抽离出来,或者利用高阶函数完成更多操作。 在前文手写快递单中,我们的需求是添加按钮,选择快递打印快递单等(实际上快递单打印部分的代码很多),不幸的是不仅是一个页面需要使用打印快递单的功能,有十个页面都需要。而且打印快递单的逻辑与页面中的逻辑混杂在一起,很不方便。这时候脑海中灵光一现,高阶函数一下子就蹦了出来。通过高阶函数抽离代码,使得维护成本降低。首先我们将打印的代码放在项目中。

//打印的代码
import React  from 'react';
import { expressHtml } from './ExpressHtml';
 
export default class Test extends React.Component{

    constructor(props){
        super(props);
        this.state={
            //由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
            //由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
            printerValue:0,
            pageValue:undefined
        }
    }

    componentDidMount(){
        if(typeof CLODOP!=="undefined" && typeof LODOP!=="undefined"){
      
            CLODOP.Create_Printer_List(this.selectRefs);
            CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
        }
    }



    handlePrint=()=>{
    
        //const MODE="PREVIEW";
        //const MODE="PRINT_DESIGN";
        const MODE="PRINT";
        this.demoPrint(MODE)
    }

    demoPrint=(MODE)=>{//MODE对应着LODOP的预览、打印以及设计
        const {printerValue }=this.state;
        const MarkDestination="586 216  ";
        const LogisticCode="7720052644695844";
        const PackageName="萍乡中转包";
        const OrderCode="FH191209007";
        const Sender={
            Name: "刘德华",
            Mobile: "17798680131",
            ProvinceName: "江苏省",
            CityName: "苏州市",
            ExpAreaName: "昆山市",
            Address: "花桥镇家宝路608号  工业园H库"
        }
        const Receiver={
            Name: "赵先生",
            Mobile: "15245451110",
            ProvinceName: "江西省",
            CityName: "萍乡市",
            ExpAreaName: "莲花县",
            Address: "陕西省某个地方",
        }
        const Onecode=`<div style="font-size:0;position:relative;width:200px;height:30px;">
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
        <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
        </div>`

        const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);

        if(typeof CLODOP==="undefined"){
            alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
            return;
        }

        LODOP.SET_PRINTER_INDEXA(Number(printerValue));
        LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);

        if(MODE){
            LODOP[MODE]();
        }
    }

    handleChangePrinter=(e)=>{
        this.setState({
            printerValue: e.target.value,
            pageValue: undefined
        }, () => {
            if (typeof CLODOP !== "undefined") {
                CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
            }
        })
    }

    handleChangePage=(e)=>{
        this.setState({
            pageValue: e.target.value
        })
    }
    
    render(){

        const styleObj={
 
            justifyContent:"center",
            alignItems:"center",
            fontSize:50,
            color:'skyblue',
            width:'100%',
            height:'100%',
            backgroundColor:"blue",
        }

        const buttonObj={
             
            border: 'none',
            borderRadius:'2px',
            background:'#e0e0e0',
            color:'inherit',
            display: 'inline-flex',
            justifyContent: 'center',
            alignItems: 'center',
            whiteSpace: 'nowrap',
            fontWeight:500,
            height: '32px',
            padding: '0 15px',
            fontSize: '14px',
            outline: 0,
            position: 'relative',
            textDecoration:'none',
            transition:'all .3s ease',
            opacity:1,
            cursor:'pointer',
            backgroundColor: 'rgba(91,231,196)',
            opacity:1,
            color:'white',
            boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'
 
        }

        const selectObj={
            border: "1px solid #d9d9d9",
            padding: "4px 0"
        }
    
        return(
            <div style={styleObj}>
                <div style={{width:"100%"}}>Hello React</div>
           
                <div style={{width:"100%"}}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>

                <select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>

                <select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
            </div>
        )
    }
}
//快递单的html
export function expressHtml(LogisticCode,MarkDestination,PackageName,Sender,Receiver,Onecode,OrderCode,Remark=""){
    return `<html style="overflow:hidden;"><head><style>.item{position:absolute;}</style></head><body style="position:relative;overflow:hidden;">
    <div class="item vline" style="left:1px;top:1px;height:479px;width:0;border-left:1px solid #000;"></div>
    <div class="item hline" style="left:1px;top:1px;width:278px;height:0;border-top:0.909091px solid #000"></div>
    <div class="item vline" style="left:279px;top:1px;height:479px;width:0;border-left:1px solid #000;"></div>
    <div class="item hline" style="left:2px;top:50px;width:278px;height:0;border-top:0.909091px solid #000"></div>
    <div class="item hline" style="left:1px;top:280px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item text" style="left:5px;top:35px;width:148.011364px;height:12.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible">2019-09-11</div>
    <div class="item text" style="left:68.9943px;top:100.98px;width:154.011364px;height:17.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${LogisticCode}</div>
    <div class="item hline" style="left:2px;top:122px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item hline" style="left:1px;top:163px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item hline" style="left:1px;top:203px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item hline" style="left:1px;top:479px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item text" style="left:39.9972px;top:348px;width:232.011364px;height:16.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible"></div>
    <div class="item text" style="left:164.5px;top:5px;width:65.011364px;height:19.011364px;font-family:'微软雅黑';font-size:13px;font-weight:800;overflow:visible;display:none">代收货款:</div>
    <div class="item text" style="left:164.5px;top:26px;width:61.011364px;height:20.011364px;font-family:'微软雅黑';font-size:14px;font-weight:400;overflow:visible;display:none"></div>
    <div class="item text" style="left:237.486px;top:460px;width:46.011364px;height:17.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">已验视</div>
    <div class="item text" style="left:5px;top:127px;width:270.011364px;height:50.011364px;font-family:'微软雅黑';font-size:26px;font-weight:400;overflow:visible">${MarkDestination}</div>
    <div class="item hline" style="left:1.99432px;top:320px;width:278px;height:0;border-top:0.994318px solid #000"></div>
    <div class="item hline" style="left:1.99432px;top: 360px;width:278px;height:0;border-top:0.994318px solid #000;"></div>
    <div class="item image" style="left: 34.4886px;top: 325.983px;width: 243px;height: 49px;">${Onecode}</div></body></html>
    <div class="item text" style="left:3.99719px;top: 365.989px;width:39.011364px;height:16.011364px;font-family:'微软雅黑';font-size:10px;font-weight:400;overflow:visible">备注:</div>
    <div class="item text" style="left:5px;top:384px;width:269.011364px;height:81.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">订单编号:${OrderCode?OrderCode:"空"}</div>
    <div class="item text" style="left:5px;top:401px;width:230.011364px;height:79.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:hidden">劳保用品<br /><span style="font-size:16px;font-weight: 600;">需本人签收,禁止投放驿站</span></div>
    <div class="item text" style="left:5px;top:438px;width:230.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:hidden">${Remark}</div>
    <img class="item image" style="left:5px;top:169px;width:30px;height:30px;"   rb319WBVhDOFORiabxDKJdnHYSuE8HVdBx/C58cYbJ4uiVWGGmqkI2iac79StliDCEuK5tPIL1/KVd7LmNRClpojJshUZGlrp18u/ZguRSjmbvTWnNoyO0qwdUr+K6xwGNI5SaKvPdSi5EAityMrAlNpFXxKxIlpjUGrbXFYy5hGUwal55eFKBhDiuSCf0g1qQfQ+gtV+N9C4hdiMUJYBCTGoxjZChUNQsjqt8rKUIIqq2mExhpBKelJnFaxa75ufr88MTW0yPsamb6L0EpNxEcsHhgYIhiAar5GU/cknn7wnFQS4he9lIo0hZhv0pcFgyVpC0L4/F8B92ANjOXNJmGB0OWNTu4dUyvcSEwHJbheHOWpNIT7jTDUxr3jFK5rHPvaxe35T GtfRS7zYnpHOpELFdwXmYiHomRR5GiLVwSZac7UUaDFqRGVzH0rtLsjmd+TCVml0gtid4c7bwe0SgSo67W9tnSUe379CH2urUrVt7feGUEnXbaaUk8I24pkE0Ey38Sx3Tn3OhTP5Eo79rcv+iasGR1cOpTAbosvHwwS3U38VtUur/+9a9PHKO2VZtqlm2XZYxIQm8MF5YofZgHAxDPXjw4WZ/bgQLGE9+SS7Ld2aQYQ4wVOr+GqgHkRJ2idOeOP+YE4cdxB9rGVohXOsJv/qdDU6zGiKc HUQVdOqG8Agew3ub0q0rXGiuS6XIGjVpZVmcQMwq61NMKskcgonbfAJFMd+JORpJV1B4/7CA q3j+X2TElOxZp+Ay0MLL5nU9uEDxcnIL7KDuBJeRkGFXcj9eup97R1L+BynmcVbTrPB8AAAAAElFTkSuQmCC">
    <div class="item text" style="left:44.4972px;top:169.977px;width:230.011364px;height:37.011364px;font-family:'微软雅黑';font-size:18px;font-weight:400;overflow:visible">${PackageName}</div>
    <div class="item text" style="left:39px;top:210px;width:236.011364px;height:68.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${Receiver.Name} ${Receiver.Mobile} ${Receiver.ProvinceName} ${Receiver.CityName} ${Receiver.ExpAreaName} ${Receiver.Address}</div>
    <div class="item text" style="left:37.4972px;top:283.989px;width:236.011364px;height:35.011364px;font-family:'微软雅黑';font-size:12px;font-weight:400;overflow:visible">${Sender.Name} ${Sender.Mobile} ${Sender.ProvinceName} ${Sender.CityName} ${Sender.ExpAreaName} ${Sender.Address}</div>
     style="color:white;left:235.923px;top:6.96022px;width:0px;height:0px;font-family:'微软雅黑';font-size:15px;font-weight:900;overflow:visible;display:none">货到付款</div>
    <div class="item image" style="left: 34.4886px;top: 65.983px;width: 243px;height: 49px;">${Onecode}</div></body></html>
    `
}

可以看出正常运行。接下来我们再改造。我们在src目录下新建components目录。新建一个js用来写我们的高阶组件。由上得出高阶函数是一个函数,传入原组件,返回一个新组件。大致我们可以得出以下的高阶组件模型。那

import React from "react";

export default (WrappedComponent)=>{

    class NewComponent extends React.Component {
        render(){

            const newProps={

            }

            return <WrappedComponent {...newProps}/>
        }
    }

    return NewComponent
    
}

然后我们分析一下哪些东西是所有打印快递单页面共用的。

1. 打印按钮以及相关联

//高阶组件
import React from "react";

export default (WrappedComponent) => {

    class NewComponent extends React.Component {

        constructor(props){
            super(props);
            this.state={
                //由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
                //由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
                printerValue:0,
                pageValue:undefined
            }
        }

        componentDidMount(){
            
        }

        handlePrint = () => {

            //const MODE="PREVIEW";
            //const MODE="PRINT_DESIGN";
            const MODE = "PRINT";
            this.demoPrint(MODE)
        }

        demoPrint = (MODE) => {//MODE对应着LODOP的预览、打印以及设计
            const { printerValue } = this.state;
            const MarkDestination = "586 216  ";
            const LogisticCode = "7720052644695844";
            const PackageName = "萍乡中转包";
            const OrderCode = "FH191209007";
            const Sender = {
                Name: "刘德华",
                Mobile: "17798680131",
                ProvinceName: "江苏省",
                CityName: "苏州市",
                ExpAreaName: "昆山市",
                Address: "花桥镇家宝路608号  工业园H库"
            }
            const Receiver = {
                Name: "赵先生",
                Mobile: "15245451110",
                ProvinceName: "江西省",
                CityName: "萍乡市",
                ExpAreaName: "莲花县",
                Address: "陕西省某个地方",
            }
            const Onecode = `<div style="font-size:0;position:relative;width:200px;height:30px;">
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
            </div>`

            const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);

            if (typeof CLODOP === "undefined") {
                alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
                return;
            }

            LODOP.SET_PRINTER_INDEXA(Number(printerValue));
            LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);

            if (MODE) {
                LODOP[MODE]();
            }
        }


        render() {
            const buttonObj = {

                border: 'none',
                borderRadius: '2px',
                background: '#e0e0e0',
                color: 'inherit',
                display: 'inline-flex',
                justifyContent: 'center',
                alignItems: 'center',
                whiteSpace: 'nowrap',
                fontWeight: 500,
                height: '32px',
                padding: '0 15px',
                fontSize: '14px',
                outline: 0,
                position: 'relative',
                textDecoration: 'none',
                transition: 'all .3s ease',
                opacity: 1,
                cursor: 'pointer',
                backgroundColor: 'rgba(91,231,196)',
                opacity: 1,
                color: 'white',
                boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'

            }

            const buttonElement =(
                <div style={{ width: "100%" }}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>
            )

            const newProps = {
                buttonElement,
            }

            return <WrappedComponent {...newProps} />
        }
    }

    return NewComponent

}
//改造后的打印页面
import React  from 'react';
import { expressHtml } from '../utils/ExpressHtml';
 
export default class Test extends React.Component{

    constructor(props){
        super(props);
        this.state={
            //由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
            //由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
            printerValue:0,
            pageValue:undefined
        }
    }

    
    handleChangePrinter=(e)=>{
        this.setState({
            printerValue: e.target.value,
            pageValue: undefined
        }, () => {
            if (typeof CLODOP !== "undefined") {
                CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
            }
        })
    }

    handleChangePage=(e)=>{
        this.setState({
            pageValue: e.target.value
        })
    }
    
    render(){

        const styleObj={
 
            justifyContent:"center",
            alignItems:"center",
            fontSize:50,
            color:'skyblue',
            width:'100%',
            height:'100%',
            backgroundColor:"blue",
        }

         
        const selectObj={
            border: "1px solid #d9d9d9",
            padding: "4px 0"
        }
    
        return(
            <div style={styleObj}>
                <div style={{width:"100%"}}>Hello React</div>
           
                {this.props.buttonElement}

                <select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>

                <select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
            </div>
        )
    }
}

这是我们发现页面的打印按钮不见了,那是不是我们写错了呢?其实不然,因为我们还没有将高阶函数导入进来呢!

我们将高阶函数导入

import TypingPage from '../../component/TypingPage';

页面中使用高阶函数有2种方法:

  1. 将组件包裹导出
export default TypingPage(Test);
  1. 使用装饰器语法
@TypingPage
class Test extends React.Component{}

当然直接这么写是会报错的,因为它不识别es装饰器语法,需要借助babel来转化。

npm install @babel/plugin-proposal-decorators --save-dev

//.babelrc
"plugins":[
        ["@babel/plugin-proposal-decorators", { "legacy": true }]
]

这下子重启可以看到

2. 选择打印机按钮以及相关联

最后打印高阶组件变成下面这样

import React,{Fragment } from "react";

export default (WrappedComponent) => {

    class NewComponent extends React.Component{

        constructor(props){
            super(props);
            this.state={
                //由于初始化时我们需要创造打印机的纸张,所以我们需要打印机的value,
                //由于操作系统打印机的顺序是由0开始的所以我们初始化时设置0
                printerValue:0,
                pageValue:undefined
            }
        }

        componentDidMount(){
            if(typeof CLODOP!=="undefined" && typeof LODOP!=="undefined"){
      
                CLODOP.Create_Printer_List(this.selectRefs);
                CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
            }
        }

        handlePrint = () => {

            //const MODE="PREVIEW";
            //const MODE="PRINT_DESIGN";
            const MODE = "PRINT";
            this.demoPrint(MODE)
        }

         
    
        
        handleChangePrinter=(e)=>{
            this.setState({
                printerValue: e.target.value,
                pageValue: undefined
            }, () => {
                if (typeof CLODOP !== "undefined") {
                    CLODOP.Create_PageSize_List(this.pageRefs, this.state.printerValue);
                }
            })
        }
    
        handleChangePage=(e)=>{
            this.setState({
                pageValue: e.target.value
            })
        }

        demoPrint = (MODE) => {//MODE对应着LODOP的预览、打印以及设计
            const { printerValue } = this.state;
            const MarkDestination = "586 216  ";
            const LogisticCode = "7720052644695844";
            const PackageName = "萍乡中转包";
            const OrderCode = "FH191209007";
            const Sender = {
                Name: "刘德华",
                Mobile: "17798680131",
                ProvinceName: "江苏省",
                CityName: "苏州市",
                ExpAreaName: "昆山市",
                Address: "花桥镇家宝路608号  工业园H库"
            }
            const Receiver = {
                Name: "赵先生",
                Mobile: "15245451110",
                ProvinceName: "江西省",
                CityName: "萍乡市",
                ExpAreaName: "莲花县",
                Address: "陕西省某个地方",
            }
            const Onecode = `<div style="font-size:0;position:relative;width:200px;height:30px;">
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:0px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:3px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:8px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:11px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:15px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:18px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:22px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:26px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:29px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:33px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:37px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:42px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:44px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:47px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:51px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:55px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:58px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:62px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:66px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:69px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:74px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:77px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:81px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:86px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:88px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:92px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:96px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:99px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:103px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:106px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:110px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:114px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:117px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:121px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:125px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:129px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:132px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:137px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:139px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:143px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:147px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:150px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:154px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:159px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:161px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:165px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:169px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:172px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:176px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:178px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:183px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:187px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:3px;height:30px;position:absolute;left:192px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:1px;height:30px;position:absolute;left:196px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:2px;height:30px;position:absolute;left:198px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
            <div style="background-color:black;width:0px;height:30px;position:absolute;left:200px;top:0px;">&nbsp;</div>
            </div>`

            const html = expressHtml(LogisticCode, MarkDestination, PackageName, Sender, Receiver, Onecode, OrderCode);

            if (typeof CLODOP === "undefined") {
                alert("系统检测出你没有启动打印设备或者端口号设置错误!!");
                return;
            }

            LODOP.SET_PRINTER_INDEXA(Number(printerValue));
            LODOP.ADD_PRINT_HTM(0, 0, "100%", "100%", html);

            if (MODE) {
                LODOP[MODE]();
            }
        }


        render() {
            const buttonObj = {

                border: 'none',
                borderRadius: '2px',
                background: '#e0e0e0',
                color: 'inherit',
                display: 'inline-flex',
                justifyContent: 'center',
                alignItems: 'center',
                whiteSpace: 'nowrap',
                fontWeight: 500,
                height: '32px',
                padding: '0 15px',
                fontSize: '14px',
                outline: 0,
                position: 'relative',
                textDecoration: 'none',
                transition: 'all .3s ease',
                opacity: 1,
                cursor: 'pointer',
                backgroundColor: 'rgba(91,231,196)',
                opacity: 1,
                color: 'white',
                boxShadow: '0 2px 2px 0 rgba(0,0,0,0.14), 0 1px 5px 0 rgba(0,0,0,0.12), 0 3px 1px -2px rgba(0,0,0,0.2)'

            }
            const selectObj={
                border: "1px solid #d9d9d9",
                padding: "4px 0"
            }
            const buttonElement =(
                <div style={{ width: "100%" }}><button style={buttonObj} onClick={this.handlePrint}>测试打印</button></div>
            )

            const selectElement=(
                <Fragment>
                    <select style={selectObj} ref={ref => this.selectRefs = ref} value={this.state.printerValue} size="1" onChange={this.handleChangePrinter}></select>

                    <select style={selectObj} ref={ref => this.pageRefs = ref} value={this.state.pageValue} size="1" onChange={this.handleChangePage}></select>
                </Fragment>
            )

            const newProps = {
                buttonElement,
                selectElement
            }

            return <WrappedComponent {...newProps} />
        }
    }

    return NewComponent

}

而需要增加打印按钮的页面只需要增加三行

import React  from 'react';
import TypingPage from '../../component/TypingPage';
 
@TypingPage
class Test extends React.Component{

    render(){

        const styleObj={
 
            justifyContent:"center",
            alignItems:"center",
            fontSize:50,
            color:'skyblue',
            width:'100%',
            height:'100%',
            backgroundColor:"blue",
        }
    
        return(
            <div style={styleObj}>
                <div style={{width:"100%"}}>Hello React</div>
           
                {this.props.buttonElement}

                {this.props.selectElement}
            </div>
        )
    }
}
export default Test;

以后需要打印快递单功能的页面只需要增加这三行,且不需要做额外的修改。是不是very nice呢?

3.高阶函数生命周期函数探究

我们在高阶函数和被包裹组件内部打印2个典型生命周期函数componentDidMountcomponnetWillMount,和渲染函数render

如图高阶组件的挂载流程很像是一个洋葱模型,知道被包裹的组件渲染完毕以后再结束高阶函数的渲染。

这样就会给实际运行的代码造成一个问题,如果在被包裹组件中有一个state是我们在包裹组件中所需要的,那我们该如何进行传递呢?有的人会说可以将state提升至高阶函数中,但是再现有项目中,如果有很多个state被使用,而且state的逻辑相当复杂,我们抽离也是需要时间的,而且代码会变得很混乱,不仅如此,假设提升至高阶函数中,实际工作中我们有很多个装饰器包裹在组件上:

这样进行传props肯定是很繁琐的。 我们可以这样做。

//创建报错状态的类并导出实例化的对象
class GlobalState {
    bindState(thz) {
        this.thz = thz
    }

    getState() {
        return this.thz
    }
}

export default new GlobalState;
//在被包裹组件的componentDidMount中
 
 componentDidMount(){
        globalState.bindState(this);
 }
 //在需要使用的地方即可
 globalState.getState()