react高阶组件的使用教程和应用场景附源码
今天咱们来说说react的高阶组件,当然咱们先要知道什么是高阶组件,它的应用场景是什么?为什么要有高阶组件的存在。
什么是高阶组件?
我们学js的时候接触过高阶函数, 高阶组件其实是差不多的用法,只不过传入的参数变成了react组件,并返回一个新的组件。
如果不知道什么是高阶函数那么看一下下面的例子:
function demo(){
  return function(){
     console.log('abc');
  }
}
demo()();
可以看到在demo函数里面又返回了一个函数这个就是高阶函数。
那么react的高阶组件如何使用呢?
高阶组件分两种形式:
1、属性代理(Props Proxy)
属性代理是最常见的高阶组件的使用方式,上述描述的高阶组件就是这种方式。它通过做一些操作,将被包裹组件的props和新生成的props一起传递给此组件,这称之为属性代理。
属性代理有如下4点常见作用:
1. 操作props
2. 通过refs访问组件实例
3. 提取state
4. 用其他元素包裹WrappedComponent,实现布局等目的
proxy.js代码如下:
import React from 'react';
import withHeader from '../../common/hoc/withHeader';
class HocComponent extends React.Component{
    constructor(){
        super();
        this.state={
            name:"张三"
        }
    };
    render(){
        return (
            <div>
                <div id="proxy">
                    我是一个属性代理的方式高阶组件<br />
                    {/*withHeader传过来的值:{this.props.name}*/}
                </div>
            </div>
        )
    }
}
export default withHeader(HocComponent,'属性代理高阶组件');
withHeader.js代码如下:
import React from 'react';
import ReactDom from "react-dom";
export default function withHeader(WrappedComponent,title) {
    return class HOC extends React.Component {
        constructor(props){
            super(props);
            this.state={
                name2:"属性代理方式"
            }
        }
        componentDidMount(){
            //获取proxy.js里面的id="proxy"的元素
            let WC=new WrappedComponent();
            let superRender=WC.render();
            let oList=ReactDom.findDOMNode(document.getElementById(superRender.props.children.props.id));
            console.log(oList.innerHTML);
        }
        render() {
            return (
                <React.Fragment>
                    <div>标题{title}</div>
                    <WrappedComponent {...this.props} name={this.state.name2}/>
                </React.Fragment>
            )
        }
    }
}
 return class HOC extends React.Component可以看到属性代理继承的是React.Component。
 
2、继承反转(Inheritance Inversion)
这种方式返回的React组件继承了被传入的组件,所以它能够访问到的区域、权限更多,相比属性代理方式,它更像打入组织内部,对其进行修改。
extend.js代码如下:
import React from 'react';
import withHeader from '../../common/hoc/extendHeader';
class HocComponent extends React.Component{
    constructor(){
        super();
        this.state={
            nickname:"张三"
        }
    };
    render(){
        return (
            <div>
                <div id="list">
                    <ul>
                        <li>我是一个反向继承的方式高阶组件</li>
                    </ul>
                </div>
            </div>
        )
    }
}
export default withHeader(HocComponent,"反向继承高阶组件");
extendHeader.js代码如下:
import React from 'react';
import ReactDom from 'react-dom';
export default function withHeader(WrappedComponent,title) {
    return class HOC extends WrappedComponent {
        constructor(){
            super();
        }
        componentDidMount(){
            //console.log(this.props);
            //可以使用extend.js里面的nickname
            console.log(this.state.nickname);
            //获取extend.js里面的id="list"的元素
            let superRender=super.render();
            let oList=ReactDom.findDOMNode(document.getElementById(superRender.props.children.props.id));
            console.log(oList.innerHTML);
        }
        render() {
            return super.render();
            // return (
            //     <React.Fragment>
            //         <div>标题{title}</div>
            //         <WrappedComponent {...this.props}/>
            //     </React.Fragment>
            // )
        }
    }
}
return class HOC extends WrappedComponent可以看到反向继承的是WrappedComponent组件。
配合有状态组件和无状态组件实战使用:
hoc.js代码如下:
import React from 'react';
import withHeader from '../../common/hoc/hocsHeader';
const WitHeader=withHeader((hocTag)=>{
    return (
        <div>我是第一个高阶组件{hocTag.children}</div>/*用hocTag.children获取name="hoc1"组件里面的内容*/
    )
});
const WitHeader2=withHeader(({children})=>{
    return (
        <div>我是第二个高阶组件{children}</div>/*用{children}获取name="hoc2"组件里面的内容*/
    )
});
const WitHeader3=withHeader((props)=>{
    return (
        <div>
            <input type="text" {...props.nickname} placeholder="输入昵称" />
            <br />
            <input type="text" {...props.pwd} placeholder="输入密码" />
        </div>
    )
});
export default class HocComponent extends React.Component{
    constructor(){
        super();
        this.state={
        }
    };
    setHoc1(){
        console.log("setHoc1");
    }
    setHoc2(){
        console.log("setHoc2");
    }
    render(){
        return (
            <div>
                <WitHeader {...this.props} name="hoc1" onClick={this.setHoc1.bind(this)}>
                    <div style={{color:"#FF0000"}}>
                        <ul>
                            <li>我是高阶组件1里面的内容</li>
                        </ul>
                    </div>
                    <div style={{color:"#0000FF"}}>
                        <ul>
                            <li>我是高阶组件1里面的内容</li>
                        </ul>
                    </div>
                </WitHeader>
                <WitHeader2 name="hoc2" onClick={this.setHoc2.bind(this)}>
                    <div style={{color:"#0000FF"}}>
                        <ul>
                            <li>我是高阶组件2里面的内容</li>
                        </ul>
                    </div>
                </WitHeader2>
                <WitHeader3></WitHeader3>
            </div>
        )
    }
}
hocsHeader.js代码如下:
import React from 'react';
export default function hocsHeader(WrappedComponent) {
    return class HOC extends React.Component {
        constructor(props){
            super(props);
            this.state={
                name:"hocsHeader",
                nickname:"",
                pwd:''
            }
        }
        componentDidMount(){
            let wrap=this.refs['wrap'];
            console.log(wrap.offsetHeight);
        }
        //获取点击事件
        getClick(){
            //接收父组件hocs.js里面的onClick事件
            if (this.props.onClick){
                this.props.onClick();
            }
        }
        changeNickname(event){
            this.setState({nickname:event.target.value},()=>{
                console.log(this.state.nickname);
            });
        }
        changePwd(event){
            this.setState({pwd:event.target.value},()=>{
                console.log(this.state.pwd);
            });
        }
        render() {
            //给hocs.js里面的WitHeader3的input添加onChange事件
            const newProps={
                nickname:{
                    value:this.state.nickname,
                    onChange:this.changeNickname.bind(this)
                },
                pwd:{
                    value:this.state.pwd,
                    onChange:this.changePwd.bind(this)
                }
            }
            return (
                <React.Fragment>
                    <div ref="wrap" onClick={this.getClick.bind(this)}>
                        <WrappedComponent {...this.props} {...newProps} />
                        {/*{this.props.children}*/}{/*获取组件hocs.js组件WitHeader和WitHeader2的内容*/}
                    </div>
                </React.Fragment>
            )
        }
    }
}
源码下载

