Reputation: 2850
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
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