七进七出React高阶组件

为何要使用高阶组件?

想一想之前用原生和jQuery的项目,上千行的code映入眼帘,瞬间有种昏死过去的冲动。代码难以维护,改一个bug可能出现N个bug,真的是很痛苦。因而乎组件化成为了当前前端开发的主流技术。angular、vue和react很好的帮咱们实现了组件化。前端

可是咱们经常也会遇到一种状况,就是两个组件每每有不少的重复代码(多是相同的属性,也多是相同的方法)。例如,在登陆和注册组件中,都会有用户名和密码,以及对他们的校验规则。为了提升代码的复用性和可维护性,React高阶函数应运而生。vue

React以前对此的解决方案是mixin,但这形成和不少没必要要的问题,后来就被废弃掉了。使用过vue的同窗,不知道有没有使用过mixin,react高阶函数的做用和它是同样的。react

高阶组件究竟是个什么东西?

高阶组件实际上是一个函数,它并非一个组件,咱们须要向它传递一些参数(想要操做的组件、属性)。这么提及来它其实一点也不高阶,它的做用就是存储一些公共的属性和方法。chrome

咱们常常几我的吃过一个锅底的那种火锅,锅底里有火锅底料和各类佐料,咱们把肉和蔬菜等放进去涮一下,就能够美美的饱餐一顿。高阶函数在react编程中扮演的角色就是火锅锅底的角色,它有公用的方法和属性,而各类组件就是肉和蔬菜。若是是一我的一个锅的火锅就像没有通过封装的code,代码量重复且维护困难。编程

如何实现高阶函数?

咱们先来看一段可使用高阶函数的代码:react-router

这里有一个Second组件,它负责展现用户名username函数

export class Second extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        });
    }
    render() {
        return(
            <div>
                <legend>Second Page</legend>
                <h2>Hi {this.state.username}</h2>
            </div>
        )
    }
}

下面是一个Third组件,它也负责展现用户名组件化

export class Third extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            username: ''
        }
    }
    componentWillMount() {
        let username = localStorage.getItem('username');
        this.setState({
            username: username
        });
    }
    render() {
        return(
            <div>
                <legend>Third Page</legend>
                <h2>Hi {this.state.username}</h2>
                <p>我今年18岁了</p>
            </div>
        )
    }
}

咱们看到这两个组件除了名称之外,其他大量的代码是同样的,咱们彻底能够考虑将它们通用的代码提取出来。下面就是高阶组件出场的时候了。this

高阶组件能够写成这样spa

export const HighOrderComponent = (WrapComponent, title) => {
    return class HOC extends React.Component {
        constructor(props) {
            super(props);
            this.state = {
                username: ''
            }
        }
        componentWillMount() {
            let username = localStorage.getItem('username');
            this.setState({
                username: username
            });
        }
        static displayName = `HOC(${getDisplayName(WrapComponent)})`;
        render() {
            return(
                <div>
                    <legend>{title}</legend>
                    <WrapComponent username={this.state.username}></WrapComponent>
                </div>
            )
        }
    }
}
  • WrapComponent 是咱们要操做的组件
  • title 是它们的标题参数
  • username 就是咱们经常使用的props,它负责向组件传递值,咱们下面还会提到

使用高阶组件以后咱们要对Second和Third组件进行修改,修改以下

class Second extends React.Component {
    render() {
        return(
            <div>
                <h2>Hi {this.props.username}</h2>
                <h3>晓不晓得哪里好耍</h3>
            </div>
        )
    }
}
export const HighOrderSecond = HighOrderComponent(Second, 'Second Page');
class Third extends React.Component {

    render() {
        return(
            <div>
                <h2>Hi {this.props.username}</h2>
            </div>
        )
    }
}
export const HighOrderThird = HighOrderComponent(Third, 'Third Page');

不少同窗可能会问,export出去的常量是干什么用的,它就是高阶组件对组件进行封装以后的一个全新的组件,是二者的结合。到此,咱们在其它页面引用组件就再也不是引用Second和Third组件了,要引用的就是HighOrderSecond和HighOrderThird了。

细心的同窗可能会发现一些不一样的地方,对于Second和Third的公共legend提取出去了,但并无将h2对应得标题提取出去,这里只是想给你们说一下,在对组件使用高阶组件包裹以后,高阶组件就变成了组件的父组件,它的state能够经过props的方式向子组件传递,username就是这样。咱们在chrome的react插件中能够观察到这一点

HOC已经将Second组件包裹起来,成为了它的父组件,它上面的match和location是我使用了react-router的缘故,咱们能够不用去管它。它的state——username做为props传给了Second

今天给你们简单的介绍了React高阶组件的一些知识,后续还会再深刻的挖掘React高阶组件的知识和你们分享,但愿对你们有帮助。文章转自我的掘金帐号,转载请注明出处,谢谢

相关文章
相关标签/搜索