高阶组件

2019-07-25  本文已影响0人  隐号骑士

高阶函数:接受一个或多个函数并返回一个函数

var add = function (x) {
      return function (y) {
          return x + y;
      }
 }
add(1)(2); // 3

JS中,array的map、filter、reduce等方法就是高阶函数的例子

var numbers = [1, 2, 3, 4];
function double(num) {
    return num * 2;
}
var doubledNumbers = numbers.map(double); //[2,4,6,8]

高阶函数的应用---柯里化

一道经典面试题

写一个add方法实现以下效果

add(1) //1
add(1)(2) //3
add(1)(2)(3) //6
add(1)(2)(3)(4) //10

答案之一:

function add(a) {
    function sum(b) { // 使用闭包
        a = a + b; // 累加
        return sum;
    }
    sum.toString = function() { // 重写toString()方法
        return a;
    }
    return sum; // 返回一个函数
}

这里的add就是高阶函数

高阶组件:接受一个组件并返回一个组件

实现方式 1 属性代理

    const Container = (WrappedComponent) =>
        class extends React.Component {
            render() {
                let newProps = { status: 'ok' }
                return <WrappedComponent {...this.props} {...newProps} />
            }
        }

实现方式 2 反向继承

    const Container = (WrappedComponent) =>
        class extends WrappedComponent {
            render() {
                return super.render()
            }
        }

Tips: super语法:
1 super([arguments]); // 访问父对象上的构造函数
2 super.functionOnParent([arguments]); // 访问对象上的方法

高阶组件使用方式

class App extends React.Component {
  render() {
    return (
      <div>
        ...
      </div>
    )
  }
}

export default Container(App);

or Decorator方式

@Container
class App extends React.Component {
  render() {
    return (
      <div>
        ...
      </div>
    )
  }
}

Tips: ES6装饰器的说明:

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

高阶组件的应用:

高阶组件应用之react-redux里的connect

import React, { Component } from 'react'
import PropTypes from 'prop-types'

const connect = (mapStateToProps)=>(WrappedComponent) => {
  class Connect extends Component {
    static contextTypes = {
      store: PropTypes.object
    }

    constructor () {
      super()
      this.state = { allProps: {} }
    }

    componentWillMount () {
      const { store } = this.context
      this._updateProps()
      store.subscribe(() => this._updateProps())
    }

    _updateProps () {
      const { store } = this.context
      let stateProps = mapStateToProps(store.getState())
      stateProps.dispatch=store.dispatch
      this.setState({
        allProps: { // 整合普通的 props 和从 state 生成的 props
          ...stateProps,
          ...this.props
        }
      })
    }
    render () {
      return <WrappedComponent {...this.state.allProps}/>
    }
  }

  return Connect
}

export default connect

使用connect

import React, { PureComponent } from 'react';
import { connect } from 'dva';
import LoginForm from './LoginForm';

@connect(({ login, loading }) => ({
    login,
    loading,
}))
export default class Login extends PureComponent {
    render() {
        const { dispatch, loading } = this.props;
        return (
            <LoginForm
                isLoading={loading.effects['login/login']}
                onOk={(data) => {
                    dispatch({
                        type: 'login/login',
                        payload: {
                            ...data,
                        },
                    });
                }}
            />
        );
    }

注意:
1、不要在render中构建高阶组件

render() {
  // 每次调用 render 函数都会创建一个新的 EnhancedComponent
  // EnhancedComponent1 !== EnhancedComponent2
  const EnhancedComponent = enhance(MyComponent);
  // 这将导致子树每次渲染都会进行卸载,和重新挂载的操作!
  return <EnhancedComponent />;
}

2、注意添加原组件的静态方法

function enhance(WrappedComponent) {
  class Enhance extends React.Component {/*...*/}
  // 必须准确知道应该拷贝哪些方法 :(
  Enhance.staticMethod = WrappedComponent.staticMethod;
  return Enhance;
}

3、ref和key不会被传递

上一篇下一篇

猜你喜欢

热点阅读