Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 548
besrabasant Avatar asked Nov 26 '17 07:11

besrabasant


People also ask

Should you use react cloneElement?

React. cloneElement() is useful when you want to add or modify the props of a parent component's children while avoiding unnecessary duplicate code.

What is the difference between createElement and cloneElement?

createElement is the code that JSX gets compiled or converted into and is used by reacting to create elements. cloneElement is used for cloning elements and passing them new props. This method is used to describe how the User Interface looks. This method is used to manipulate the elements.

How do you duplicate components in react?

Rather than creating a new component instance (if we already have one), sometimes we'll want to copy it or add custom props/children to the component so we can retain the same props it was created with. We can use React. cloneElement() to handle this for us.


1 Answers

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.

like image 111
Prakash Sharma Avatar answered Sep 24 '22 18:09

Prakash Sharma