Adding a prop to previously defined component using React.cloneElement error cannot read properties of undefined

636 Views Asked by At

I have a component defined as Attack in a file named dice.js. In some instances I want a specific prop (m) to be filled out automatically

dice.js

...
export function Attack({ n, h, d, m = '' }) {
  return (
    <div>foob, {`${n} ${h} ${d} ${m}`}</div>
  );
}
...other components...

This component is then imported into into an mdx file for users to add to their posts:

post.mdx

blah blah blah <Attack n="foo" h="bar" d="foobar" /> // no 'm' prop

Great. Works perfectly. BUT!

There is a place where I want to add another prop that will always be filled in so that users don't have to type it out and I'm having trouble understanding why it doesn't work:

search.js

...imports...

// I don't want users to have to use a different tag so I imported it with a different name.
// Then I will rename it to the original name with the added prop.

import {Attack as SearchAttack} from './dice';

...

const Attack = React.cloneElement(
  SearchAttack(),
  { m: 'name' },
);

...

// A component that renders markdown from YAML front matter that users fill their content with. 
// This works when I don't attempt to add a prop and import the component with its normal name.

<MarkdownView components={ Attack } markdown={content} />

But the page always loads with an error: Error in function Attack in ../PATH/TO/COMPONENT/dice.js: Cannot read properties of undefined (reading 'n')

I don't know why this is occurring. I've checked the front matter and it is formatted like this:

post.mdx

...stuff...
<Attack n="foo" h="bar" d="foobar" />
...

I expect it to receive the new prop along with the previously defined props.

<div>foob, foo bar foobar name</div>

2

There are 2 best solutions below

0
On

I ended up not using React.cloneElement at all and instead used this amazing solution to adding props: https://stackoverflow.com/a/68946448/3609711

2
On

You tried to clone a thing that is expected to be a react element. But what you supplied to it as a parameter is not a jsx (see SearchAttack() from the code block below).

const Attack = React.cloneElement(
  SearchAttack(), // THIS IS NOT RIGHT!
  { m: name },
);

You tried to run a component function as a function (and specified no arguments to it, btw). To create a valid jsx you should use createElement