paul23
paul23

Reputation: 9435

Why is the syntax for higher order components in react often of the Higher Order Function form? Instead of extra arguments?

Well I wonder, why, in react, we often see higher order components of the form:

MyComponent = withSomeHOC(params)(function MyActualCompoent(props) {
    return <div/>
})

And the implementation might look like:

function withSomeHOC(params, modifier) {
    function(WrappedComponent) {
        return function(props) {
            //do whatever to modify something based on params.
            const data = modifier(React.useContext(someCTX));
            return <>
                <div>{data}</div>
                <WrappedComponent {...props}/>
            </>;
        }
    }
}

Instead of the more logical approach (to me) to just add params as second (and third) parameter to the higher order component itself:

MyComponent = withSomeHOC(function MyActualComponent(props) {
    return <div/>
}, params, modifier);


function(WrappedComponent, params, modifier) {
    return function(props) {
        //do whatever to modify something based on params.
        const data = modifier(React.useContext(someCTX));
        return <>
            <div>{data}</div>
            <WrappedComponent {...props}/>
        </>;
    }
}

Why do we hardly see the second approach and nearly always the first? What is the disadvantage of the second? An advantage is a more simple program structure, instead of deeply nested higher order components and functions.

Upvotes: 0

Views: 706

Answers (3)

Nicholas Tower
Nicholas Tower

Reputation: 84922

I speculate that one reason this is so common is to make composition easier. If you are applying multiple HoCs to a single component you can end up with some hard to read code like this:

export default withLogging(withRouter(withStuff(Component, arg1a, arg2a), arg1b), arg1c);

Recompose or similar libraries can let you turn this into something more readable through a utility function called compose. compose takes a sequence of functions and calls them one at a time, passing the output of one function as the input to the next.

But in order for this to work, all of these functions must be unary (ie, they must take exactly one argument). So the reason for using the pattern you're asking about is that it lets you easily make unary functions, that only need a Component to be passed into them. Then those unary functions can be composed together.

So if withLogging, withRouter, and withStuff are rewritten to follow the pattern you describe, then they can be used as follows:

export default compose(
  withStuff(arg1a, arg2a),
  withRouter(arg1b),
  withLogging(arg1c),
)(Component)

Upvotes: 2

tksilicon
tksilicon

Reputation: 4426

I have been reading about currying of recent and this:

MyComponent = withSomeHOC(params)(function MyActualCompoent(props) {
    return <div/>
})

Looks to me like it:

function(a)(a)

From what I am reading, it is to write cleaner code. Like Nicholas said. Not sure there is any performance benefit. Here is a reference here on stackoverflow

NB: I am still a learner.

Upvotes: 0

hackape
hackape

Reputation: 19957

For the 1st form, you can config that HOC factory once, then use it elsewhere.

This is actually sorta decorator pattern.

const preConfigDecorator = withSomeHOC(config)
const DecoratedComp1 = preConfigDecorator(Comp1)
const DecoratedComp2 = preConfigDecorator(Comp2)

If your component is class base, the syntax is way more elegant:

@withSomeHOC(config)
class MyComp extends React.Component {
  …
}

Upvotes: 1

Related Questions