The art of
Higher-Order Component

黃駿朋 / dmoon / DMoon

 

 

中央資工研究所

創科資訊

dmoon.t@gmail.com

Blog

GitHub

React Native Taiwan (http://reactnative.asia)

How many of you have heard of HOC?

Add functionality to existing component classes

Why HOCs are useful?

Reusing component logic

Add reusing functionality to existing component classes

Higher-Order Component?

Higher-Order Function

Functional Programming

Function As Parameter

Higher-Order Function

A higher order function is a function that takes a function as an argument, or returns a function

A higher-order component is a function that takes a component and returns a new component.

Higher-Order Component

function HOC(WrappedComponent) {
  // abstract logic
  return <WrappedComponent enhanced={true} />;
}

const EnhancedComponent = HOC(WrappedComponent);
function HOC(WrappedComponent) {
  // returns another component
  return class extends React.Component {
    // constructor or lifecycle methods...
    render() {
      // ... and renders the wrapped component with the fresh data!
      // Notice that we pass through any additional props
      return <WrappedComponent data={this.state.data} 
              {...this.props} />;
    }
  }
}

const EnhancedComponent = HOC(WrappedComponent);

Props Proxy

Inheritance Inversion

function HOC(WrappedComponent) {
  return class Enhancer extends WrappedComponent {
    render() {
      return super.render()
    }
  }
}

const EnhancedComponent = HOC(WrappedComponent);

Render Highjacking

Examples

React-Redux

connect

connect components to Redux store

const EnhancedComp = connect(mapStateToProps)(MyComp);

Ref

HOC(MyComp);

Curry

Custom HOC

LikeButton

/* HOC */
export default WrappedComponent => class Optimistic extends Component {
  state = {
    isActive: this.props.isActive
  }
  handleOnPress = async () => {
    // optimistic update
    const originStatus = this.state.isActive;
    this.setState({ isActive: !originStatus });
    // do fetch
    let isSuccess;
    if (this.state.isActive) {
      isSuccess = await this.props.inactivate();
    } else {
      isSuccess = await this.props.activate();
    }
    if (!isSuccess) {
      this.setState({ isActive: originStatus });
    }
  }
  render() {
    return <WrappedComponent 
            {...this.props} 
            isActive={this.state.isActive} 
            onPress={this.handleOnPress} />;
  }
};

Title Text

/* Usage */
const OptimisticLikeBtn = Optimistic(LikeButton);
export default class LikeButton extends Component {
  like = async () => {
    const response = await likeRequest;
    return response.isSuccess;
  }
  unlike = async () => {
    const response = await unlikeRequest;
    return response.isSuccess;
  }
  render() {
    return (
      <OptimisticLikeBtn
        {...this.props} 
        isActive={this.props.isCollected} 
        activate={this.like} 
        inactivate={this.unlike} />
    );
  }
}

Q & A

Made with Slides.com