0

I want to create a React component that clones an HTML element by its id.

I tried several ways but every time I get an error.

const [element,setElement] = useState()

useEffect(()=>{
    setElement(document.querySelector('#svg'))
},[])

return element

Error: Objects are not valid as a React child (found: [object HTMLImageElement]). If you meant to render a collection of children, use an array instead.

const [element,setElement] = useState()

useEffect(()=>{
    let el = React.cloneElement(document.querySelector('#svg'))
    setElement(el)
},[])

return element

Error: 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.

Roman
  • 175
  • 2
  • 3
  • 15

1 Answers1

2

Be aware that querySelector() in React is an anti pattern. You should consider to use refs instead. Read more how to use refs in this thread: Using document.querySelector in React? Should I use refs instead? How?

To create a React component that clones an HTML element by its id with querySelector(), you can use React.createElement and pass it the HTML element, its tag name, and its properties as arguments.

Example:

import React, { useEffect, useState } from 'react';

const CloneElement = () => {
  const [element, setElement] = useState(null);

  useEffect(() => {
    const htmlElement = document.querySelector('#svg');
    setElement(
      React.createElement(htmlElement.tagName, {
        ...htmlElement.attributes,
        children: htmlElement.innerHTML,
      })
    );
  }, []);

  return element;
};

export default CloneElement;
Filip Huhta
  • 2,043
  • 7
  • 25
  • Don't do this, this is completely against the React route: `querySelector` should be avoided! – 0stone0 Feb 02 '23 at 15:10
  • 2
    Why is this getting upvoted???? – 0stone0 Feb 02 '23 at 15:14
  • 3
    @0stone0 you might not like the use case but that doesnt make an answer incorrect. – terpinmd Feb 02 '23 at 15:15
  • Consider using cloneNode: https://www.w3schools.com/jsref/met_node_clonenode.asp – terpinmd Feb 02 '23 at 15:16
  • Yes it does. If you know React you should also know using querySelctor is a anti pattern. – 0stone0 Feb 02 '23 at 15:17
  • @0stone0 I want to make a copy of an HTML element. I want to create a "Use" component. like in svg. It's comfortable – Roman Feb 02 '23 at 15:17
  • Not in every case it doesnt. For example integrating with a third party thing that you might need to get a hold of a dom element for. – terpinmd Feb 02 '23 at 15:18
  • Thats also wrong, but yea, who cares. Good luck. – 0stone0 Feb 02 '23 at 15:20
  • lol wrong. aight – terpinmd Feb 02 '23 at 15:20
  • 4
    The OPs question is asking for enablement of a bad practice, I think it should be warned against without making it a bad question that should be downvoted. This answer enables a bad practice, it should include warnings about this being an anti-pattern and even advise against using it, but again does not necessarily make it a bad answer that should be downvoted. Warnings are useful to future readers and therefore have value on SO – Brian Thompson Feb 02 '23 at 15:21
  • @BrianThompson I want to ask. If the "Use" component becomes an exact copy of another component, is this a bad practice? – Roman Feb 02 '23 at 15:26
  • 2
    I'm not sure what a "Use" component is. It's also important to understand that an HTML element and a React element are very different things - so here you are not dealing with a "copy" of anything, but a component modeled after some element. I would say unless there is some very obscure edge case here that I'm missing, this would not be a good practice – Brian Thompson Feb 02 '23 at 15:29