React cloneElement is not working for functional component

10k Views Asked by At

I would like to add some props to my component using {React.cloneElement(<MyComponent />, { onClick: () => console.log('click'), style: {background: 'red'} })}

Full code:

const MyComponent = () => {
  return (
    <div>
      foooo
    </div>
  );
};

....
return React.cloneElement(<MyComponent />, { onClick: () => console.log('click'), style: {background: 'red'} })

But props are not passed into my component.

When I use:

return React.cloneElement(<div>foooo</div>, { onClick: () => console.log('click'), style: {background: 'red'} })

Props are working. Why? I don`t understand why.

2

There are 2 best solutions below

3
On

Why would you use cloneElement when you got JSX available (can conclude it from MyComponents syntax).

Instead do:

<MyComponent
  onClick={() => console.log("click")}
  style={{ background: "red" }}
/>

And fix your component:

const MyComponent = ({ style, onClick }) => {
  return <div onClick={onClick} style={style}>foooo</div>;
}

JSX is sugar syntax for createElement / cloneElement.

React.cloneElement(
  element,
  [props],
  [...children]
)

React.cloneElement() is almost equivalent to:

<element.type {...element.props} {...props}>{children}</element.type>

Therefore the right syntax:

const onClick = () => console.log('click');
const style = {background: 'red'};

// Exatcly the same effect as <MyComponent .../> above
React.cloneElement(<MyComponent/>, {onClick, style}, null);

Edit intelligent-architecture-9modf

0
On

You need to apply props inside you component:

export const Test = (props: any) => {
  return (<button {...props}>Click Me</button>);
}

In this case you can set props using

React.cloneElement(<MyComponent/>, props, null);

but I do not recommend cloning (it is too heavy) I think that it is better to use special render function in props:

export const Wrapper = (props: {render: (props: any) => any}) => {
    const childProps = {style: {background: 'red'}, onClick: () => { console.log('click'); }};
    if (props.render){
      return props.render(childProps);
    } else {
      return <></>;
    }
  }
// ...
// usage:
export default function App() {      
  return (
    <div className="App">      
      <Wrapper render={(props)=>{
        return <button {...props}>TEST</button>;
      }}/>      
    </div>
  );
}