Functions are not valid as a React child

Functions are not valid as a React child
0

#1

I ran into this error recently while trying conditional rendering, here hoping if anyone could actually explain this behavior, here’s the code:

renderDeleteColumn = (user, movie, onDelete) => {
    if (user && user.isAdmin) {
      return (
        <td>
          <button
            onClick={() => onDelete(movie)}
            className="btn btn-danger btn-sm"
          >
            Delete
          </button>
        </td>
      );
    }
  };

render() {

const { movies, onDelete, user } = this.props;

 return (
   <tbody>
     {movies.map(movie => (
      <tr key={movie._id}>
       <td>{movie.genre.name}</td>
       {() => this.renderDeleteColumn(user, movie, onDelete)}
      </tr>
    ))}
  </tbody>
 )
}

So basically I am trying to render the column of a table based on if the user is logged in and is an admin, but my method is not working as expected.

Just to be clear, I know I can use use inline logical && operator to render this condition or the ternary operator, but I am curious as way a method would not work?


#2

Just an idea, the expression in the brackets is simply creating a new anonymous function:

{() => this.renderDeleteColumn(user, movie, onDelete)}

but the function you created is not being invoked, nothing should happen if you do it this way.
Perhaps just writing

{this.renderDeleteColumn(user, movie, onDelete)}

will do the trick.


#3

Put it in a function and render the component. The technique is called render props (you pass a function that returns a React element as a prop). You aren’t rendering a component, so what your doing isn’t going to work (you thing you pass as a function has to have a render method)


#4

If his function is simply returning JSX within a render function, it should be ok.
For sure the expression in the brackets isn’t doing anything except creating an anonymous function and then not doing anything with it.

Putting an else clause in the function would help to see if it is something is happening when user && user.isAdmin is false.


#5

HarplingeTom is quite right in his first answer. You can just use

{this.renderDeleteColumn(user, movie, onDelete)}

or alternatively with a slight tweak, you can turn your function into a functional component, which is a more preferred way in React.

const DeleteColumn = (props) => {
// You can destructure ^^^^ here, but i prefer it below. 
// Ultimately, it's up to you. 
    const {user, movie, onDelete} = props;
    if (user && user.isAdmin) {
      return (
        ... // nothing changes here
      );
    }
  };

render() {

const { movies, onDelete, user } = this.props;

 return (
   <tbody>
     {movies.map(movie => (
      <tr key={movie._id}>
       <td>{movie.genre.name}</td>
      <DeleteColumn 
            user={user} 
            movie={movie}, 
            onDelete={onDelete}
       {/* or you could just  {...this.props} /*}
       />
      </tr>
    ))}
  </tbody>
 )
}