7

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?

8
  • why do you want to use cloneElement? Commented Nov 26, 2017 at 7:15
  • @SaeidAlidadi Because I want to pass props from Component B to Component A... say it somewhat requirement of my project. Commented Nov 26, 2017 at 7:18
  • 1
    I think you should use HOC for this purpose Commented Nov 26, 2017 at 7:19
  • @SaeidAlidadi So you are suggesting me to make Component B a HOC Commented Nov 26, 2017 at 7:22
  • So what does CloneElement do exactly? I have seen examples of using the function to clone children of React Components. @SaeidAlidadi Commented Nov 26, 2017 at 7:28

1 Answer 1

17

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Understood. Very well explained.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.