besrabasant
besrabasant

Reputation: 2850

React.CloneElement returning an object instead of function

I am having a hard time understanding the behaviour of React.cloneElement() function

I have my Component Structure something like this

A.js

export default class A extends React.Component {
     render() {
         return (<h1>{ this.props.message }</h1>)
     }
 }

B.js

import A from "./A"

const newComponent = React.cloneElement(A,{
    message: "Hello World"
})

export default newComponent

C.js

import B from "./B"
import { BrowserRouter as Router, Route } from "react-router-dom"

// To Be very precise
 export default class C extends React.Component {
     render() {
         return (
             <Router>
                <Route path="/" component={B}  />
            </Router>
         )
     }
 }

But I get this Error

Invalid prop component of type object supplied to Route, expected function.

but When I pass Component A directly into the Route component, it renders fine.

When I console.log Component A inside the render function of Component C, I get a function but When I console.log Component B inside the render function of Component C, I get a object

What am I missing?

Upvotes: 7

Views: 12061

Answers (1)

Prakash Sharma
Prakash Sharma

Reputation: 16472

First you need to understand the difference between React component and React element.Both are actually different.

To be specific in jsx, in your case, A is a react component and <A /> is a react element. If you look at the React.cloneElement docs, then it expect an element as a first argument, but here you are passing a component. So first change you need to do is to pass an element to React.cloneElement like this

const newComponent = React.cloneElement(<A />,{
    message: "Hello World"
})

The second thing is that the Route component expects a react component as component prop, but React.cloneElement returns a react element instead of component (that means newComponent is an element, not component). Therefore you cannot just simply export newComponent from the B.js file. You have to export a component instead. For that you can create a class component/stateless component. So your B.js should look something like this

// B.js
import A from "./A"

const newComponent = React.cloneElement(<A />, {
  message: "Hello World"
})

export default class B extends React.Component {
  render() {
    return (<div>{newComponent}</div>)
  }
}

By the way, you don't even need cloneElement here in your case. You can simply return a component from B.js which render A. This is just for understanding purpose.

Upvotes: 17

Related Questions