Understanding React Higher-Order Components

6.3k views Asked by At

Can someone please explain Higher-order components in React. I have read and re-read the documentation but cannot seem to get a better understanding. According to the documentation, HOCs help remove duplication by creating a primary function that returns a react component, by passing arguments to that function. I have a few questions on that.

  • If HOCs create a new enhanced component, can it be possible not to pass in any component as argument at all?
  • In an example such as this, which is the higher order component, the Button or the EnhancedButton.
  • I tried creating one HOC like this:

    // createSetup.js
    import React from 'react';
    
    export default function createSetup(options) {
        return class extends React.Component {
            constructor(props) {
                super(props);
    
                this.state = {};
    
                this.testFunction = this.testFunction.bind(this);
            }
    
            testFunction() {
                console.log("This is a test function");
            }
    
            render() {
                return <p>{options.name}</p>
            }
        }
    }
    
    
    // main.js
    import React from 'react';
    import {render} from 'react-dom';
    import createSetup from './createSetup';
    
    render((<div>{() => createSetup({name: 'name'})}</div>),
            document.getElementById('root'););
    

Running this does not show the HOC, only the div

Can anyone help out with a better example than the ones given?

5

There are 5 answers

5
Josep On BEST ANSWER

A HOC is a function that takes a Component as one of its parameters and enhances that component in some way.

If HOCs create a new enhanced component, can it be possible not to pass in any component as argument at all?

Nope, then it wouldn't be a HOC, because one of the conditions is that they take a component as one of the arguments and they return a new Component that has some added functionality.

In an example such as this, which is the higher order component, the Button or the EnhancedButton.

EnhanceButton is the HOC and FinalButton is the enhanced component.

I tried creating one HOC like this: ... Running this does not show the HOC, only the div

That's because your createSetup function is not a HOC... It's a function that returns a component, yes, but it does not take a component as an argument in order to enhance it.

Let's see an example of a basic HOC:

const renderWhen = (condition, Component) =>
  props => condition(props)
    ? <Component {...props} />
    : null
);

And you could use it like this:

const EnhancedLink = renderWhen(({invisible}) => !invisible, 'a');

Now your EnhancedLink will be like a a component but if you pass the property invisible set to true it won't render... So we have enhanced the default behaviour of the a component and you could do that with any other component.

In many cases HOC functions are curried and the Component arg goes last... Like this:

const renderWhen = condition => Component =>
  props => condition(props)
    ? <Component {...props} />
    : null
);

Like the connect function of react-redux... That makes composition easier. Have a look at recompose.

0
Curro González On

Try your createSetup.js with:

const createSetup = options => <p>{options.name}</p>;

and your main.js

const comp = createSetup({ name: 'name' });
render((<div>{comp}</div>),
  document.getElementById('root'));
1
Henok Tesfaye On

In short, If you assume functions are analogues to Components, Closure is analogous to HOC.

0
ABHIJEET KHIRE On
// HIGHER ORDER COMPOENTS IN REACT
// Higher order components are JavaScript functions used for adding 
// additional functionalities to the existing component.


// file 1:  hoc.js (will write our higher order component logic) -- code start -->

const messageCheckHOC = (OriginalComponent) => {
  // OriginalComponent is component passed to HOC

  const NewComponent = (props) => {

    // business logic of HOC 
    if (!props.isAllowedToView) {
      return <b> Not Allowed To View The MSG </b>;
    }

    // here we can pass the props to component
    return <OriginalComponent {...props} />;
  };

  // returning new Component with updated Props and UI
  return NewComponent;
};

export default messageCheckHOC;

// file 1:  hoc.js  -- code end -->


// file 2: message.js  -- code start -->
// this is the basic component we are wrapping with HOC 
// to check the permission isAllowedToView msg if not display fallback UI

import messageCheckHOC from "./hoc";

const MSG = ({ name, msg }) => {
  return (
    <h3>
      {name} - {msg}
    </h3>
  );
};

export default messageCheckHOC(MSG);
// file 2: message.js  -- code end -->


// file 3 : App.js -- code start --->
import MSG from "./message.js";

export default function App() {
  return (
    <div className="App">
      <h3>HOC COMPONENTS </h3>
      <MSG name="Mac" msg="Heyy !!! " isAllowedToView={true} />
      <MSG name="Robin" msg="Hello ! " isAllowedToView={true} />
      <MSG name="Eyann" msg="How are you" isAllowedToView={false} />
    </div>
  );
}

// file 3 : App.js -- code end --->

output

0
Khabir On

A higher-order component (HOC) is an advanced technique in React for reusing component logic. Concretely, a higher-order component is a function that takes a component and returns a new component.

A HOC is a pure function with zero side-effects.

Example: CONDITIONALLY RENDER COMPONENTS

Suppose we have a component that needs to be rendered only when a user is authenticated — it is a protected component. We can create a HOC named WithAuth() to wrap that protected component, and then do a check in the HOC that will render only that particular component if the user has been authenticated.

A basic withAuth() HOC, according to the example above, can be written as follows:

// withAuth.js
import React from "react";
export function withAuth(Component) {
    return class AuthenticatedComponent extends React.Component {
        isAuthenticated() {
            return this.props.isAuthenticated;
        }

        /**
         * Render
         */
        render() {
            const loginErrorMessage = (
                <div>
                    Please <a href="/login">login</a> in order to view this part of the application.
                </div>
            );

            return (
                <div>
                    { this.isAuthenticated === true ? <Component {...this.props} /> : loginErrorMessage }
                </div>
            );
        }
    };
}

export default withAuth;

The code above is a HOC named withAuth. It basically takes a component and returns a new component, named AuthenticatedComponent, that checks whether the user is authenticated. If the user is not authenticated, it returns the loginErrorMessage component; if the user is authenticated, it returns the wrapped component.

Note: this.props.isAuthenticated has to be set from your application’s logic. (Or else use react-redux to retrieve it from the global state.)

To make use of our HOC in a protected component, we’d use it like so:

// MyProtectedComponent.js
import React from "react";
import {withAuth} from "./withAuth.js";

export class MyProectedComponent extends React.Component {
    /**
     * Render
     */
    render() {
        return (
            <div>
                This is only viewable  by authenticated users.
            </div>
        );
    }
}

// Now wrap MyPrivateComponent with the requireAuthentication function 
export default withAuth(MyPrivateComponent);

Here, we create a component that is viewable only by users who are authenticated. We wrap that component in our withAuth HOC to protect the component from users who are not authenticated.

Source