0

Context

I am building a React app (rails-react) where I have a parent component GameTracker that has some child components; namely, EquipmentPanel and PinnedPanels. I have added a pinned-panels-container div in the parent component where I want to move panels from the EquipmentPanel when I click on a 'pin' button.

        <div id='container'>

          <EquipmentPanel pinPanel={this.pinPanel}/>

          <div id='tracker-contents'>
            {this.state.pinnedPanels.length > 0 && 
           <div id='pinned-panels-container'>
              <h2>Pinned Panels</h2>
                {this.state.pinnedPanels}
           </div>}

          </div>
        </div>

Approach

The way I plan to do this is create a pinPanel() function in the parent component GameTracker, and pass it as a prop to its child, EquipmentPanel. The child then adds the button, and calls pinPanel(div), with div being the specific div/panel I want to pin.

pinPanel(panel) {
    let newPanel = panel.current.cloneNode(true)

    var parser = new DOMParser();
    var htmlDoc = parser.parseFromString(newPanel.innerHTML, 'text/html');
    newPanel = htmlDoc
    
    let newPinnedPanels = this.state.pinnedPanels

    newPinnedPanels.push(newPanel)
   
    this.setState({
      pinnedPanels: newPinnedPanels
    })
   
  }

Error

Now, whenever I pin a panel, React gives me:

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

If I try to use an array, as the error message recommends, I get the same error. If I don't use DOMParser(), (which I found here), I get the same error, with the following difference: found: [object HTMLDivElement].

My question is, is there any way in React to clone a div with all its contents, pass it to another component through state, and render it in another component that is not its parent or child? I basically want to copy/paste a div.

Edit: If I try to assign it by .innerHTML, the end result is a panel with [object HTMLDocument] as a string inside.

Grimhamr
  • 41
  • 6

1 Answers1

0

Unsure if this is considered a proper answer, but I made it work with DOM manipulation. Feels hacky, but it works. If someone has any insight, it is of course welcome.

let newPanel = panel.current.cloneNode(true)

    if (this.pinnedPanelsRef.current.innerHTML.includes(newPanel.children[0].innerHTML)) {
      this.pinnedPanelsRef.current.innerHTML = this.pinnedPanelsRef.current.innerHTML.replace(newPanel.children[0].innerHTML, "")

    }
    else {
      this.pinnedPanelsRef.current.innerHTML += newPanel.children[0].innerHTML
    }

I still feel like there is a much more elegant solution that I am failing to reach.

Grimhamr
  • 41
  • 6