Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass data between 2 React DOM

In a website, I have multiple react rendering elements. I want to pass the data between this 2 individual elements. What are the possible options for passing the data between 2 elements

ReactDOM.render(<Header/>, document.getElementById('header'));
ReactDOM.render(<SideBar/>, document.getElementById('sidebar'));

I want to have a single data storage between these elements. Like I get data in one component and I want that data to be accessible in all the elements (in all ReactDOM). So what can be the possible options for this?

Edit: Due to requirement I can't merge them in to same root component. Only some portion of page is in react other is still in the HTML/Jquery. So I render them individually in the required div.

Does redux store work between different ReactDOMs?

like image 689
hardiksa Avatar asked Apr 25 '18 13:04

hardiksa


2 Answers

Use Portals from the react-dom library:

Portals provide a first-class way to render children into a DOM node that exists outside the DOM hierarchy of the parent component.


const HeaderPortal = ReactDOM.createPortal(<Header />, document.getElementById('header'))
const SideBarPortal = ReactDOM.createPortal(<SideBar />, document.getElementById('sidebar'))

const store = createStore(/* ... */)

ReactDOM.render(
  <YourDataStoreProvider store={store}>
    <HeaderPortal />
    <SideBarPortal />
  </YourDataStoreProvider>, 
  document.getElementById('root') // assuming you have an empty "dummy" node with that id
);

Just render you app into a container anywhere in your DOM or create a new "dummy" node. In my example I assume there is an empty node with the id root. Then render your other components into a portal.

Does redux store works between different ReactDOMs?

Your app will work as if it was rendered entirely into the same container. If you use Portals your components will be in the same component tree having the same context while being rendered somewhere else.

Should I use Portals?

Using Portals usually is intended to be used for components that visually need to "break out" of its container like modals or dialogs. But you can also use them to create widget-like components that can be rendered anywhere.

Creating a generic Portal component

You can also create a generic <Portal> component that creates a portal given a container id:

import {createPortal} from 'react-dom';

const Portal = ({children, container}) => createPortal(
    children,
    document.getElementById(container),
);

export default Portal;

And use it this way:

ReactDOM.render(
  <YourDataStoreProvider store={store}>
    <Portal container="header">
      <Header />
    </Portal>
    <Portal container="sidebar">
      <SideBar />
    </Portal>
  </YourDataStoreProvider>, 
  document.getElementById('root')
);

EDIT:

You need one node in the DOM where you can render your app. This can be a new DOM element that you create or it can be one of the containers you already have. Given you use the <Portal> component from above it could also look like this:

ReactDOM.render(
    <YourDataStoreProvider store={store}>
        <Header /> // this will be visible in your header container
        <Portal container="sidebar">
            <SideBar /> // this will be rendered to the sidebar container
        </Portal>
    </YourDataStoreProvider>, 
    document.getElementById('header')
);

This will render your app in the header container. But only your <Header> component will actually have a DOM representation in that container. The sidebar will be rendered in the sidebar container by the portal. But still they will share the same react component tree and have the same store provider.

like image 193
trixn Avatar answered Nov 13 '22 09:11

trixn


You can create a component container and have both as a child and render them separate. Exchange the data through props and the mother container.

I provide an example:

https://codepen.io/hkares/pen/rvLPzQ

HTML

//html
<header id="header"></header>
<main>
  <nav id="nav"></nav>
  <section>I am section</section>
</main>
<footer>This is a footer</footer>
<div id="useless"></div>

Index.js

const HEADER_NODE = document.querySelector("#header");
const NAVBAR_NODE = document.querySelector("#nav");

const Header = ({ name }) => ReactDOM.createPortal(<h1>{name}</h1>, HEADER_NODE);

const NavBar = (props) => ReactDOM.createPortal(
  <article>
    <label>
      Set header name: <input {...props} />
    </label>
  </article>
, NAVBAR_NODE);

class Container extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "this is a header"
    };
  }

  onChange = ({ target }) => this.setState({ value: target.value });

  render() {
    const { value } = this.state;
    return (
      <React.Fragment>
        <Header name={value} />
        <NavBar value={value} onChange={this.onChange} />
      </React.Fragment>
    );
  }
}

ReactDOM.render(
  <Container />,
  document.querySelector("#useless")
);
like image 22
Tomeu Cabot Avatar answered Nov 13 '22 10:11

Tomeu Cabot