I get an error every time I try to add a child element (div) of a button via cloneElement
. This error is:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it’s defined in, or you might have mixed up default and named imports.
When I use an imported component like:
const clonedElement = cloneElement(
<Test />
);
it works fine
but it doesn’t work with event.currentTarget.children[0]
Why is this happening? Am I missing something?
Here is the code:
const [CurrentIndex, setCurrentIndex] = useState(0);
const [Symbols, setSymbols] = useState([{ symbols: [] }]);
const appendToCurrent = (event) => {
const clonedElement = cloneElement(
event.currentTarget.children[0]
);
setSymbols(prev =>
Object.assign([], prev, {
[CurrentIndex]: {
symbols: [...prev[CurrentIndex].symbols, clonedElement]
}
}))
}
<button onClick={event => appendToCurrent(event)}><div>A</div></button>
<button onClick={event => appendToCurrent(event)}><div>B</div></button>
{Symbols.map((field, i) => {
return (
<div key={i}>
<div onClick={() => setCurrentIndex(i)}>
{field.symbols.map((symbol, i) => {
return (
<div key={i}>
{symbol}
</div>
);
})}
</div>
</div>
);
})}
2
Answers
The
event.currentTarget
parameter doesn’t return React components – it’s a basic vanilla JS object that will therefore return the actual parts of the DOM (the actual HTML elements) instead. In order to clone based on who was clicked, you should pass another parameter besidesevent
that will contain the actual component. Something like this:You can build the divs dynamically to avoid creating many variables.
There is a problem with how you used the
cloneElement
function, the type ofevent.currentTarget.children[0]
isElement
andcloneElement
doesn’t accept it as an argument. But, apart from this issue, the way you aim to achieve the result isn’t the best way, for sure.You can simply keep the contents you want to render as an array of texts rather than keeping HTML/React nodes in a state which is a BAD practice.