Qar
Qar

Reputation: 1804

React - parent component with child in separate dom containers

Is it possible to have a component with child components that will be mounted to different DOM objects?

Some pseudo-code to explain what I wanna archieve:

import ChildComponent1 from './Components/ChildComponent1';
import ChildComponent2 from './Components/ChildComponent2';

var MyParentComponent = React.createClass({
  render: function() {
    <ChildComponent1 />,
    document.querySelector('#component-1')

    <ChildComponent2 />,
    document.querySelector('#component-2')
  }
});

ReactDOM.render(
  <MyParentComponent />,
  //Inherit DOM mounts
);

This might not be the right way to handle it though - I'm open for suggestions. I want to do like this, to make MyParentComponent take care of the state values etc. If I just add multiple ReactDOM.render() I won't have any parent component.

Upvotes: 3

Views: 2922

Answers (4)

SimpleJ
SimpleJ

Reputation: 14768

You can achieve this using the componentDidMount and componentDidUpdate hooks to manually render your child components when your parent component updates:

class Child1 extends React.Component {
  render() {
    const {count, onClick} = this.props;
    return (
      <div onClick={onClick}>Child 1 {count}</div>
    );
  }
}

class Child2 extends React.Component {
  render() {
    const {count, onClick} = this.props;
    return (
      <div onClick={onClick}>Child 2 {count}</div>
    );
  }
}

class App extends React.Component {
  constructor(props) {
    super(props);
    this.container1El = document.querySelector("#container-1");
    this.container2El = document.querySelector("#container-2");
    this.handleClick = this.handleClick.bind(this);
    this.state = {count: 0};
  }

  handleClick() {
    this.setState({count: this.state.count + 1});
  }

  renderChildren() {
    const {count} = this.state;
    const {handleClick, container1El, container2El} = this;
    ReactDOM.render(<Child1 count={count} onClick={handleClick}/>, container1El);
    ReactDOM.render(<Child2 count={count} onClick={handleClick}/>, container2El);
  }

  componentDidMount() {
    this.renderChildren();
  }
  
  componentDidUpdate() {
    this.renderChildren();
  }
  
  componentWillUnmount() {
    ReactDOM.unmountComponentAtNode(this.container1El);
    ReactDOM.unmountComponentAtNode(this.container2El);
  }

  render() {
    return null;
  }
}

ReactDOM.render(<App/>, document.createElement("div"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="container-1"></div>
<div id="container-2"></div>

Upvotes: 2

Sebastien Lorber
Sebastien Lorber

Reputation: 92112

What you are looking for is a portal.

Sometimes it is useful to render a child element to a different dom tree than the natural one. For example you may want the child to get appended to body, generally for z-index or opacity reasons.

I've described it here: https://stackoverflow.com/a/31563614/82609

Consider the following:

<div className="a">
    a content
    <Portal target="body">
        <div className="b">
            b content
        </div>
    </Portal>
</div>

Could produce the following DOM when rendered inside reactAppContainer:

<body>
    <div id="reactAppContainer">
        <div className="a">
             a content
        </div>
    </div>
    <div className="b">
         b content
    </div>
</body>

Popular portal libraries are:

  • react-portal, useful for simple portals like popups/full screen layers.
  • react-tether, useful for "positioned portals" (ie relative to their parent) like tooltips, dropdowns, hotspots...

Upvotes: 2

Shubham Khatri
Shubham Khatri

Reputation: 281616

No need to create a parent component, you can use ReactDOM.render() multiple times

import ChildComponent1 from './Components/ChildComponent1';
import ChildComponent2 from './Components/ChildComponent2';


ReactDOM.render(
  <ChildComponent1 />,
  document.getElementById('component-1')
);

ReactDOM.render(
  <ChildComponent2 />,
  document.getElementById('component-2')
);

UPDATE

In order to have multiple components in one you can have your structure as:

import ChildComponent1 from './Components/ChildComponent1';
import ChildComponent2 from './Components/ChildComponent2';

var MyParentComponent = React.createClass({
  render: function() {
  return(
   <div>
    <ChildComponent1 />
    <div>Some text</div>
    <div>Some more text</div>
    <ChildComponent2 />
   </div>
  )}
});

ReactDOM.render(
  <MyParentComponent />,
  document.getElementById('app');
);

Upvotes: 0

r0dney
r0dney

Reputation: 745

The answer is no, it's not possible. This is the best you can do if you still want to use React for that.

var MyParentComponent = React.createClass({
  render: function() {
    <div>
      {this.props.children}
      <ChildComponent1 />
      <ChildComponent2 />
    </div>
  }
});

ReactDOM.render(
  <MyParentComponent />,
  //Inherit DOM mounts
);

Upvotes: -1

Related Questions