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>
)
}
}
}
源码下载