Anton
Anton

Reputation: 37

Issue with higher order components: A valid React element (or null) must be returned

Why does the higherOrderComponent1 function doesn't work and the higherOrderComponent2 works as expected? According the documentation I don't seem to be doing something wrong, but as it is not working, I must be doing something wrong :-)

https://facebook.github.io/react/docs/higher-order-components.html

You can find a sandbox version here: https://codesandbox.io/s/MRwMnA2R

import React, {Component} from 'react';
import {render} from 'react-dom';

const higherOrderComponent1 = (name) => {
  return class extends Component {
    render() {
      <div>{`Hi ${name}`}</div>
    }
  }
};

const higherOrderComponent2 = (name) => (
  <div>{`Hi ${name}`}</div>
);


const App = () => (
  higherOrderComponent1("Peter")
);

render(<App />, document.getElementById('root'));

Upvotes: 0

Views: 857

Answers (1)

Kyle Richardson
Kyle Richardson

Reputation: 5645

Ok you're a little off on how to use a HOC. Here is a simplistic example that I will explain.

function giveColor( WrappedComponent, color ) {
    return class extends Component {    
        componentDidMount() {
            this.wrapperEl.children[ 0 ].style.color = color;
        }

        render() {
            console.log(this.props)
            return (
                <div ref={ ( el ) => this.wrapperEl = el }>
                    <WrappedComponent { ...this.props } />
                </div>
            );
        }
    }
}

const PrintName = ({ name }) => (
    <div>{ name }</div>
);

const PrintRedName = giveColor( PrintName, "#ff0000" );

You would use PrintRedName as follows: <PrintRedName name="Bubowski" />

The name property you provide will get passed through to the wrapped component because of the { ...props } on the <WrappedComponent /> call in the render method of the returned class from the HOC.

The HOC is used as a function on another component as follows: const PrintRedName = giveColor( PrintName, "#ff0000" );

I'm calling the giveColor HOC with PrintName component as the first argument, and the color I want to set as the second.

In the HOC I wrap the WrappedComponent in a div that I give a ref that I use to change the style.color property of the first child of the ref.

This is a contrived example, but I hope it helps you understand :)

Some good examples of HOCs are connect() from react-redux and withRouter() from react-router

EDIT: In response to your latest question:

I edited your linked to code to the following to make it work, please read the in code comments.

const wrapComponent = (WrappedComponent) =>
  class extends Component {
    render() {
      return (
        <div>
          I wrapped:
          <WrappedComponent {...this.props} />
        </div>
      )
    }
  }

const ComponentA = ({name}) => <div><b>{name}</b></div>;
const ComponentB = wrapComponent(ComponentA);

// You had...
/*

No need to wrap a component wrapping itself, but the problem here is,
You're nesting evalutions by doing { ...code } inside
() => ( single evaluation )

const App = () => (
  { wrapComponent(ComponentB) }
)
*/


const App = () => (
  <ComponentB name="My name" />
)

render(<App />, document.getElementById('root'));

Upvotes: 1

Related Questions