44

I have a React component that displays styled text, and I want to have it load a network resource, listen for WebSocket input, and display notifications. In order to do this, I write Higher Order Component wrapper functions for each of these: withResource, withSocket, and withNotifications.

When exporting the component, is this correct?

class TextComponent extends React.Component {
  ...
}

export default withResource(withSocket(withNotifications(TextComponent)))
superhawk610
  • 2,457
  • 2
  • 18
  • 27
  • May I know where are you getting this "withSocket" from? – AkshayM Jul 30 '18 at 07:32
  • 2
    It's just a theoretical example, so it doesn't exist. I imagine it would contain helper methods for sending/responding to communication over a socket, likely plugging into a library like `socket.io`. – superhawk610 Jul 30 '18 at 11:06

3 Answers3

71

You can use compose from redux or recompose. For example:

Redux

import { compose } from 'redux'

export default compose(
  withResource,
  withSocket,
  withNotifications
)(TextComponent)

Recompose

import { compose } from 'recompose'

export default compose(
  withResource,
  withSocket,
  withNotifications
)(TextComponent)
Hemerson Carlin
  • 7,354
  • 1
  • 27
  • 38
  • 1
    Excellent. I don't use redux in this project, but compose is also available in `lodash/fp`. `pipe()` should work as well, no? – superhawk610 Feb 01 '18 at 18:48
  • @superhawk610 you're welcome. [recompose](https://github.com/acdlite/recompose/blob/master/docs/API.md#compose) also offers the same utility. – Hemerson Carlin Feb 01 '18 at 18:54
  • 1
    why not use a nested approach withResource(withSocket(withNotifications(TextComponent))) – TheEhsanSarshar Sep 11 '19 at 07:58
  • 5
    @Ehsansarshar It also works. The problem with this approach is that it is harder to reason about which HOCs are being used. Specially if in the future any of these HOC change their signature. It will be harder to make the change. Imagine with you have a component with lots of HOCs: `withHOC1(withHOC2(withHOC3(withHOC4(withHOC5(withHOC6)))))`... I don't think it is readable enough. – Hemerson Carlin Sep 14 '19 at 07:44
  • 1
    This solution helped me a lot, with this example I was able to better understand the advantages of Redux to the state with React – Fernando Tholl Nov 26 '20 at 19:44
14

It's called functional composition and it has mathematical background (that causes y and x variables naming and reversed execution of functions). It decreases complexity of the way how you call written functions by eliminating variables extra definition and deep level of function wrapage.

Write it by yourself or use from a library like: lodash, rambda, redux, etc.

const compose = (...rest) => x => rest.reduceRight((y, f) => f(y), x)

Usage with first class functions:

const increment = (numb) => numb + 1
const multiplyBy = (multiplyNum) => (num) => multiplyNum * num

compose(increment, multiplyBy(3), increment)(4)// 4 > 5 > 15 > 16

Usage with higher order components:

compose(withRouter, withItems, withRefs)(Component) 
Purkhalo Alex
  • 3,309
  • 29
  • 27
8

Another simple solution can be to do this in three steps, simply putting the HOC components on top of each other like this:

const firstHOC = withNotifications(TextComponent);
const secondHOC = withSocket(firstHOC);
export default withResource(secondHOC);
Danielh
  • 173
  • 2
  • 8