skip to Main Content

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


  1. 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 besides event that will contain the actual component. Something like this:

    const appendToCurrent = (event, childComponent) => {
     const clonedElement = cloneElement(childComponent);
    
    ...
    
    const divA = <div>A</div>;
    
    <button onClick={event => appendToCurrent(event, divA)}>{divA}</button>
    

    You can build the divs dynamically to avoid creating many variables.

    Login or Signup to reply.
  2. There is a problem with how you used the cloneElement function, the type of event.currentTarget.children[0] is Element and cloneElement 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.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search