react高阶组件浅谈

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/cjg214/article/details/81335293

引入及概念

1.js中高阶函数:一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。

function add(x, y, f) {
    return f(x) + f(y);
}
//当调用add(-5, 6, Math.abs)时,参数x,y和f分别接收-5,6和函数Math.abs,根据函数定义,可以推导计算过程为:
//x = -5;
//y = 6;
//f = Math.abs;
//f(x) + f(y) ==> Math.abs(-5) + Math.abs(6) ==> 11;
//return 11;

//用代码验证一下:
add(-5, 6, Math.abs); // 11

2.类似于高阶函数,高阶组件(Higher-Order Components)概念如下:高阶组件就是一个函数,且该函数接受一个组件作为参数,并返回一个新的组件

const EnhancedComponent = higherOrderComponent(WrappedComponent);

3.应用场景

(1)react-redux的connect函数~

//把redux的state和action传进去用来创建高阶函数,
//通过props注入给了Component。
//被包装后的Component可以直接用this.props去调用redux state和action创建函数了。
ConnectedComment = connect(mapStateToProps, mapDispatchToProps)(Component);

即分解如下:

// connect是一个返回函数的函数(就是个高阶函数)
const enhance = connect(mapStateToProps, mapDispatchToProps);
// 返回的函数就是一个高阶组件,该高阶组件返回一个与Redux store
// 关联起来的新组件
const ConnectedComment = enhance(Component);

(2)antd中form表单包装

const WrappedNormalLoginForm = Form.create()(NormalLoginForm);

4.高阶组件的意义

高阶组件就是一个没有副作用的纯函数。

最普通的组件哦。
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;

问题:上面两段代码相同,都市从localstorange中拿到username,解决:写一个通用的高阶组件。

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
}

使用高阶函数封装组件:

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.不要在render里使用高阶组件。

原因:性能问题+重新加载一个组件会引起原有组件的所有状态和子组件丢失

解决:组件外使用(推荐)、构造函数里、生命周期里使用

render() {
  // 每一次render函数调用都会创建一个新的EnhancedComponent实例
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // 每一次都会使子对象树完全被卸载或移除
  return <EnhancedComponent />;
}

2.必须将静态方法做拷贝

当使用高阶组件包装组件,原始组件被容器组件包裹,也就意味着新组件会丢失原始组件的所有静态方法。

解决:

(1)将原始组件的所有静态方法全部拷贝给新组件:

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // 必须得知道要拷贝的方法 :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

点评:你需要清楚的知道都有哪些静态方法需要拷贝

(2)使用hoist-non-react-statics自动拷贝所有非React的静态方法:

import hoistNonReactStatic from 'hoist-non-react-statics';
function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  hoistNonReactStatic(Enhance, WrappedComponent);
  return Enhance;
}

(3)分别导出组件静态方法

// 替代……
MyComponent.someFunction = someFunction;
export default MyComponent;

// ……分别导出……
export { someFunction };

// ……在要使用的组件中导入
import MyComponent, { someFunction } from './MyComponent.js';

3.不能传递refs属性

refs是一个伪属性,React对它进行了特殊处理。如果你向一个由高阶组件创建的组件的元素添加ref应用,那么ref指向的是最外层容器组件实例的,而不是内层包裹组件。

使用例子后续补充。。。^_^

参考链接:

http://react-china.org/t/react-higher-order-components/14949

https://doc.react-china.org/docs/higher-order-components.html

欢迎指正!

猜你喜欢

转载自blog.csdn.net/cjg214/article/details/81335293