React进阶之高阶组件

一.介绍

1.说明:

高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件。我的理解是定义一个A组件(函数),把这个A组件传入给B组件,B组件把A组件包裹一层,然后再返回给A组件。这样的话就可以在原来的A组件上添加一些功能

高阶组件是react应用中很重要的一部分,最大的特点就是重用组件逻辑。它并不是由React API定义出来的功能,而是由React的组合特性衍生出来的一种设计模式。如果你用过redux,那你就一定接触过高阶组件,因为react-redux中的connect就是一个高阶组件。 

2.理解:

下面来一个简单的例子:

function welcome() {
    let username = localStorage.getItem('username');
    console.log('welcome ' + username);
}
 
function goodbey() {
    let username = localStorage.getItem('username');
    console.log('goodbey ' + username);
}
 
welcome();
goodbey();

我们发现两个函数有一句代码是一样的,这叫冗余唉。不好不好~(你可以把那一句代码理解成平时的一大堆代码)
我们要写一个中间函数,读取username,他来负责把username传递给两个函数。

function welcome(username) {
    console.log('welcome ' + username);
}
 
function goodbey(username) {
    console.log('goodbey ' + username);
}
 
function wrapWithUsername(wrappedFunc) {
    let newFunc = () => {
        let username = localStorage.getItem('username');
        wrappedFunc(username);
    };
    return newFunc;
}
 
welcome = wrapWithUsername(welcome);
goodbey = wrapWithUsername(goodbey);
 
welcome();
welcome();

好了,我们里面的wrapWithUsername函数就是一个“高阶函数”。
他做了什么?他帮我们处理了username,传递给目标函数。我们调用最终的函数welcome的时候,根本不用关心username是怎么来的。
我们增加个用户study函数。

function study(username){
    console.log(username+' study');
}
study = wrapWithUsername(study);
 
study();

3. 高阶组件


高阶组件就是一个没有副作用的纯函数。
我们把上一节的函数统统改成react组件。

welcome函数转为react组件。

import React, {Component} from 'react'
 
class Welcome extends Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
 
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        })
    }
 
    render() {
        return (
            <div>welcome {this.state.username}</div>
        )
    }
}
 
export default Welcome;

goodbey函数转为react组件。

import React, {Component} from 'react'
 
class Goodbye extends Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
 
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        })
    }
 
    render() {
        return (
            <div>goodbye {this.state.username}</div>
        )
    }
}
 
export default Goodbye;

现在你是不是更能看到问题所在了?两个组件大部分代码都是重复的唉。
按照上一节wrapWithUsername函数的思路,我们来写一个高阶组件(高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件)。

import React, {Component} from 'react'
 
export default (WrappedComponent) => {
    class NewComponent extends Component {
        constructor() {
            super();
            this.state = {
                username: ''
            }
        }
 
        componentWillMount() {
            let username = localStorage.getItem('username');
            this.setState({
                username: username
            })
        }
 
        render() {
            return <WrappedComponent username={this.state.username}/>
        }
    }
 
    return NewComponent
}

这样我们就能简化Welcome组件和Goodbye组件。

import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
 
class Welcome extends Component {
 
    render() {
        return (
            <div>welcome {this.props.username}</div>
        )
    }
}
 
Welcome = wrapWithUsername(Welcome);
 
export default Welcome;
import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
 
class Goodbye extends Component {
 
    render() {
        return (
            <div>goodbye {this.props.username}</div>
        )
    }
}
 
Goodbye = wrapWithUsername(Goodbye);
 
export default Goodbye;

看到没有,高阶组件就是把username通过props传递给目标组件了。目标组件只管从props里面拿来用就好了

二.高阶组件主要形式

1.装饰器

ES7中添加了一个decorator的属性,使用@符表示,可以更精简的书写。可以参考 react-redux中connet  ,


import React, {Component} from 'react';
import wrapWithUsername from 'wrapWithUsername';
 
@wrapWithUsername
class Welcome extends Component {
 
    render() {
        return (
            <div>welcome {this.props.username}</div>
        )
    }
}
 
export default Welcome;

2.主要形式

(1).属性代理

引入里我们写的最简单的形式,就是属性代理(Props Proxy)的形式。通过高价组件包装的Welcome和Goodbye,也就是例子中的Welcome和Goodbye,本来传给Welcome和Goodbye的props,都在wrapWithUsername(高阶组件)中接受到了,也就是属性操作。 由此我们可以做一些操作

如下面简单的列子:直接操作props

class Hello extends React.Component{
	render() {
		return <h2>hello</h2>
	}
}
function WrapperHello(Comp){
	class WrapComp extends React.Component{
		render() {
			return (
				<div>
					<h2>这是HOC高阶组件特有的元素</h2>
					<Comp {...this.props}></Comp>
				</div>) 
		}
	}
	return WrapComp
}
Hello = WrapperHello(Hello)

class Login extends React.Component {
	render() {
			return (
				<div>
					<Hello></Hello>
				</div>) 
		}
}
//页面显示:这是HOC高阶组件特有的元素   hello

(2).反向继承

反向继承(Inheritance Inversion),简称II。跟属性代理的方式不同的是,II采用通过 去继承WrappedComponent(被包装的组件),本来是一种嵌套的关系,结果 反向继承 返回的组件却继承了WrappedComponent(被包装的组件),这看起来是一种反转的关系。
通过继承WrappedComponent(被包装的组件),除了一些静态方法,包括生命周期,state,各种function,我们都可以得到。

如下面简单的列子:

class Hello extends React.Component{
	render() {
		return <h2>hello</h2>
	}
}
function WrapperHello(Comp){
	class WrapComp extends Comp{
		componentDidMount(){
			console.log('高阶组件新增的生命周期,加载完成')
		}
		render() {
			return (
				<div>
					<Comp  {...this.props}></Comp>
				</div>) 
		}
	}
	return WrapComp
}
Hello = WrapperHello(Hello)

class Login extends React.Component {
	render() {
			return (
				<div>
					<Hello></Hello>
				</div>) 
		}
}
//页面显示:hello  打印:高阶组件新增的生命周期,加载完成

参考:助你完全理解React高阶组件

React进阶之高阶组件

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值