In simple terms, HOC is a function that takes a component as an argument and returns a new one. HOC is primarily used for logical reuse between components. For example, if you write several components with nearly identical logic between them, you can use HOC to encapsulate and reuse the logic.

This article mainly shares:

  • How to encapsulate HOC
  • HOC + combination function to handle multiple HOC nesting problems
  • HOC + Cremation, encapsulation of multi-parameter HOC

How to encapsulate HOC

Here are a few common forms of HOC

withLogger

We often need to print props when debugging code, so we can encapsulate the print logic.

const withLogger = (prefix = "") = > WrappedComponent => {
  const WithLogger = props= > {
    console.log(`${prefix}[Props]:`, props);
    return <WrappedComponent {. props} / >;
  };
  return WithLogger;
};
Copy the code

Use:

withLogger('Here I print XXX')(Component)
Copy the code

withData

The logic to get data in the component can also be detached into HOC, requiring passing in URL and PARAM.

import React, { Component } from "react";

const withData = (url, params) = > WapperedComponent => {
  class WithData extends Component {
    state = {
      data: []}; componentDidMount() { fetch(url, {body: JSON.stringify(params)})
         .then(response= > response.json())
         .then(data= > this.setState({ data }));
    }
    render() {
      return <WapperedComponent {. this.state} {. this.props} / >;
    }
  }
  return WithData;
};

Copy the code

Use:

withData(
  url: 'https://jsonplaceholder.typicode.com/posts'.params: {
    _limit: 10.page: 2
  }
)(Component)
Copy the code

withLoading

Because the data request is asynchronous, the Loading component is displayed when the data request is not returned to prevent the user from seeing blank space.

const withLoading = Loading= > WapperedComponent => {
  const WithLoading = props= > {
    return props.data.length === 0? ( <Loading /> ) : ( <WapperedComponent {... props} /> ); }; return WithLoading; };Copy the code

Use:

const Loading = () => <p>loading</p>;
withLoading(Loading)(Component)
Copy the code

How to handle multiple HOC nesting problems

If a component needs to request data, show loading when the data is not returned, and also need to print props, we need to combine withData, withLoading, and withLogger.

const Loading = () => <p>loading</p>;
withData(
  "https://jsonplaceholder.typicode.com/posts",
  {
    _limit: 10,
    page: 2
  }
})(
  withLogger('xxx')(
    withLoading(Loading)(Component)
  )
)
Copy the code

The above nested method is not readable, so use the compose composition function to optimize it.

const compose = (... fns) => x => fns.reduceRight((x, fn) => fn(x), x); const Loading = () => <p>loading</p>; compose( withData( "https://jsonplaceholder.typicode.com/posts", { _limit: 10, page: 2}), withLogger(" here is XXX "), withLoading(Loading),)(Component);Copy the code

The optimized code is significantly easier to read, but if you’re not comfortable executing from the bottom up, you could write pipe as well. Simply change the reduceRight method in compose to reduce.

How to encapsulate HOC with multiple parameters

We notice that withData takes two arguments, url and params. If we need to call withData multiple times, for example:

withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 10,
    }
)
withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 9,
    }
)
withData(
    "https://jsonplaceholder.typicode.com/posts",
    {
      _limit: 8,})Copy the code

We find that the URL of each call is the same, so we can encapsulate the arguments with the Currization function:

const curry = fn= > {
  const loop = (. args) = >args.length === fn.length ? fn(... args) :(. arg) = >loop(... args,... arg)return loop
}

const withPostData = curry(withData)("https://jsonplaceholder.typicode.com/posts")

withPostData({_limit: 10})
withPostData({_limit: 9})
withPostData({_limit: 8})

Copy the code

Similarly, we can encapsulate withUserData, withCommentData, and so on, depending on the URL.

conclusion

  1. Using HOC to encapsulate some code logic can increase the reusability of the code and facilitate later maintenance.
  2. HOC + combine functions to improve code readability.
  3. HOC + Cremation, encapsulation of multi-parameter HOC, further increase the reusability of code.

reference

  • The React – Composing who – Order Components (HOCs)
  • Currization of JavaScript topics
  • The combination of JavaScript Functional Programming (2)
  • Higher-Order Components