higher order components (HOC)

A Higher Order Components (HOC) is a function that accepts a Component as an argument and returns a Component.  It is an advanced technique to React for reusing component logic. HOCs are a pattern that emerges from React’s compositional nature.

Examples of Higher-Order Components (HOCs)

There are many, but some notable ones:

  • The most common is probably Redux ’s functionconnect.
  • React Router ’s functionwithRouter which simply grabs the router off the context and makes it a prop for the child.
  • Map  function is an example of such a component

How to efficiently use a higher order components (HOC)

class DisplayFruitsListWise extends React.Component {
 constructor(props) {
 render() {
   return (
     <div>
       <ul class="list">
         {this.props.fruits.map(( fruit, index) => (
           return <li key={index}>{fruit}</li>
         ))}
       </ul>
     </div>
   );
 }
}

class DisplayFruitsGridWise extends React.Component {
 constructor(props) {
   super(props);
 }
 render() {
   return (
     <div>
       <ul class="grid">
         {this.props.fruits.map(( fruit, index) => (
           return <li key={index}>{fruit}</li>
         ))}
       </ul>
     </div>
   );
 }
}

.list li { width: 100%; border-bottom: 1px dotted #CCC; margin-bottom: 10px; padding-bottom: 10px; }

 .grid li { float: left; width: 20%; height: 50px; border-right: 1px dotted #CCC; border-bottom: 1px dotted #CCC; padding: 20px; }

DisplayFruitsListWise and DisplayFruitsGridWise aren’t identical — they render different output, but their implementation is the same.

 

We can write a function that creates components, like DisplayFruitsListWise and DisplayFruitsGridWise, that subscribe to user data. The function will accept as one of its arguments a child component and another param as data.

This makes the code reusable.


const DisplayFruitsListWiseWithMyData = addMyData(DisplayFruitsListWise,(data)=>{return data});
const DisplayFruitsGridWiseWithMyDataSorted = addMyData(DisplayFruitsGridWise,(data)=>{return data.sort()});
function addMyData(WrappedComponent, modify) {
 return class extends React.Component {
   constructor(props) {
     super(props);
     this.state = {
       data: modify([‘Apple’,‘Bananas’,‘Chiku’,‘Orange’,‘Pear’,‘Grapes’,‘Peach’,‘WaterMelon’]) :
     };
   }
   render() {
     return <WrappedComponent fruits = {this.state.data}/>;
   }
 };
}

 

Higher order components don’t modify the input component, nor does it use inheritance to copy its behavior. Rather, a HOC composes the original component by wrapping it in a container component. A HOC is a pure function with zero side-effects.

 

The wrapped component receives all the props of the container, along with a new prop, data, which it uses to render its output. The HOC isn’t concerned with how or why the data is used, and the wrapped component isn’t concerned with where the data came from.

 

Conventions followed, With Examples:

  1. Don’t Mutate the Original Component. Use Composition.
function log(NewComponent) {
 NewComponent.prototype.componentWillReceiveProps = function(nextProps) {
  console.log(“Adding logg to test”);
 };
 return NewComponent;// returning the component received , hence its mutated
}

There are a few problems with this. One is that the input component cannot be reused separately from the enhanced component. More crucially, if you apply another HOC to EnhancedComponent that also mutates componentWillReceiveProps, the first HOC’s functionality will be overridden! This HOC also won’t work with functional components, which do not have lifecycle methods.

Mutating higher order components (HOC) are a leaky abstraction—the consumer must know how they are implemented in order to avoid conflicts with other HOCs.

Instead of mutation, higher order components (HOC) should use composition, by wrapping the input component in a container component:

function log(WrappedComponent) {
 return class extends React.Component {
   componentWillReceiveProps(nextProps) {
    console.log('testing props--->')
   }
   render() {
     // Wraps the input component in a container, without mutating it.
     return <WrappedComponent {...this.props} />;
   }
 }
}

2. Pass Unrelated Props Through to the Wrapped Component

HOCs add features to a component. They shouldn’t drastically alter its contract. It’s expected that the component returned from a HOC has a similar interface to the wrapped component.

HOCs should pass through props that are unrelated to its specific concern. Most HOCs contain a render method that looks something like this:

render() {
 const {neededProp, ...unrelatedProps } = this.props;
 // Pass props to wrapped component
 return (
   <WrappedComponent
     data={neededProp}
     {...unrelatedProps}
   />
 );
}

This convention helps ensure that HOCs are as flexible and reusable as possible.

3. Maximizing Composability

Not all higher order components (HOC) look alike, they might take several arguments based on the input.  Functions whose output type is the same as its input type are really better to compose together. An example of a simple react redux connect:

// Whats generally followed
 const EnhancedComponent = withRouter(connect(commentSelector)(WrappedComponent))
// ... you can use a function composition utility
// compose(f, g, h) is the same as (...args) => f(g(h(...args)))
 const enhance = compose(
  // These are both single-argument HOCs
   withRouter,
   connect(commentSelector)
 )
const EnhancedComponent = enhance(WrappedComponent)

4. Wrap the Display Name for Easy Debugging

The container components created by higher order components (HOC) show up in the React Developer Tools like any other component. To ease debugging, choose a display name that communicates that it’s the result of a HOC.

The most common technique is to wrap the display name of the wrapped component. So if your higher-order component is named addMyData, and the wrapped component’s display name is DisplayFruitsListWise, use the display name addMyData(DisplayFruitsListWise):

function addMyData(WrappedComponent, modify) {
return class extends React.Component {/**/}
addMyData.displayName = `addMyData(${getDisplayName(WrappedComponent)})`;
return addMyData;
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}

 

Read also:

Portals in react js

Server-Side Rendering JavaScript – React Js

Difference between Container and Component in React.js

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

This site uses Akismet to reduce spam. Learn how your comment data is processed.