0

As far as I understand and, following the documentation, a HOC is a function that takes a component and returns a new component. An example of that is the function connect from react-redux:

connect(mapStateToProps, mapDispatchToProps)(MyComponent)

I was using Autosizer from React-virtualized and found the next definition in its documentation:

High-order component that automatically adjusts the width and height of a single child.

The syntax example used in its documentation is the next one:

ReactDOM.render(
  <AutoSizer>
    {({height, width}) => (
      <List
        height={height}
        rowCount={list.length}
        rowHeight={20}
        rowRenderer={rowRenderer}
        width={width}
      />
    )}
  </AutoSizer>,
  document.getElementById('example'),
);

Not sure if I am asking below the appropriate questions that allow me to understand what is going on. If not, I ask you to forget about those two questions and explain it in a different approach.

1) Why is Autosizer a HOC? I cannot tell it is a function receiving one component and returning another one the same way as connect in react-redux.

2) In the anonymous function ({height, width}) => {...}, height and width are properties of an object being passed. Which object and where does it come from?

fjplaurr
  • 1,818
  • 3
  • 19
  • 36
  • 1
    I don't think `AutoSizer` is an HoC, but it just uses a [_render prop_](https://reactjs.org/docs/render-props.html) for its `children` prop. – Emile Bergeron Mar 02 '20 at 19:44
  • Reading the issues on the project, it seems that the mention of it being an HoC is just an artifact from the past. It looks like some components were HoCs at some point but were changed to use _render props_ instead and not all documentation was updated to reflect this. – Emile Bergeron Mar 02 '20 at 20:30
  • @EmileBergeron Thanks. It is a bit confusing when the docs are not updated with the React docs' definitions. I Hope this question and answers may help someone in the future. – fjplaurr Mar 02 '20 at 21:57

2 Answers2

1

Another way to think of it is that Higher Order Components are higher order than their children (meaning they are closer the root of the DOM node tree), and that they render their children with modifications or providing extra information to their children.

1) Why is Autosizer a HOC?

It's more useful to think of it as a component that returns its children, but with extra info. In this case, a width and height that the child components can use to modify themselves.

But technically, in the source it does return some wrapper JSX around the children you pass in. So the component it "takes" is its children (in this case <List>) and the component it returns is a <div> with contents that it then puts your <List> inside of while providing extra information it wouldn't other wise have.

So it's not so different than connect which takes a component, and then returns components with extra props injected then it would otherwise have.

But whether or not it's an HOC really isn't that important here. It's a component that expects a function that returns JSX as its children. That's the important bit.

2) In the anonymous function ({height, width}) => {...}, height and width are properties of an object being passed. Which object and where does it come from?

First all, whatever is between the open and closing tags is that component's children. This is most commonly JSX of some sort, a pure javascript value between {} characters. This can also be a function.

So in this case, Autosizer expects its children prop to be a function. Autosizer then calls this function while rendering and passes an object with width and height as arguments.

Autosizer may have an implementation like this:

function Autosizer({children}) {
  return children({
    width: window.outerWidth,   // or some other internal logic
    height: window.outerHeight, // or some other internal logic
  })
}

This means that Autosizer has some internal logic to derive some values, and then passes those values to the function passed as children as arguments.

This pattern is called a render prop. And React has documentation about it here.


Here's a simple example of a simple HOC that provides window size to its children via render prop.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • _"Because it's a component that returns it's children"_, that's not the definition of an HoC. Here's [the definition](https://reactjs.org/docs/higher-order-components.html): **a higher-order component is a function that takes a component and returns a new component.** – Emile Bergeron Mar 02 '20 at 19:47
  • Sorry, technically you're right. But I'm not it's a useful distinction in this case. But answer updated regardless – Alex Wayne Mar 02 '20 at 19:54
  • Thank you @AlexWayne for detailed explanation. Now I understand what's happening. I will look deeply at the Render Props technique since that is the key of this matter. – fjplaurr Mar 02 '20 at 21:45
1

You can find the source code for that component here, but a simplified version would be something like this:

class AutoSizer extends React.PureComponent {
  // Do some extra stuff here to set width and height as they should be
  render() {
    return (
      <div
        // Call children as a function with the parameters calculated in this class
        {this.props.children({ height, width })}
      </div>
    );
  }
}

So you pass AutoSizer a child that is a function.

<AutoSizer>
  {({height, width}) => {
   // your custom logic here that uses height and width sent from AutoSizer
  }}
</AutoSizer>

AutoSizer gets that function as a prop, and then it calls it with some calculated parameters.

Brian Thompson
  • 13,263
  • 4
  • 23
  • 43