Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rendering components in different containers while sharing state

Tags:

reactjs

I have an HTML page pre-rendered by WordPress and three React components: <App />, <Component /> and <AnotherComponent />.

There are two ID div containers inside the HTML page (div id="component" and div id="anotherComponent") that are separated and I want to render React components on. Also they share some state. I want to use <App /> to write all the logic and event handling and then pass state (this.props.counter) to each component.

enter image description here

I would like to use ReactDOM.render(<Component />, document.getElementById('component')); for each component and use the <App /> to control the logic but how would I pass state to each component, and what would I render() in the <App />.

What is the best way to go with this one?

like image 705
pmqa Avatar asked Jun 05 '17 16:06

pmqa


People also ask

How do you handle shared state between components?

In React, sharing state is accomplished by moving it up to the closest common ancestor of the components that need it. This is called “lifting state up”. We will remove the local state from the TemperatureInput and move it into the Calculator instead.

Do components re render when state changes?

React components automatically re-render whenever there is a change in their state or props. A simple update of the state, from anywhere in the code, causes all the User Interface (UI) elements to be re-rendered automatically.

Can we use state in render method?

You can't set react state in the render function, but you can in the constructor or most of the component lifecycle functions. Show activity on this post. Never set state inside render function as it might create a side effect and it will create an infinite render cycle eventually.

What happens if you set state within the render method?

Calling setState() here makes it possible for a component to produce infinite loops. The render() function should be pure, meaning that it does not modify a component's state. It returns the same result each time it's invoked, and it does not directly interact with the browser.


Video Answer


1 Answers

ReactDOM.render is like the main method of a React application. All the react related concepts like components, state, and context starts from here. You can call ReactDOM.render multiple times on the same page with the same container DOM node or different container DOM nodes. If the container is the same, this will perform an update on it and only mutate the DOM as necessary to reflect the latest React element. But if container nodes are different, it will create two different React roots and those are totally independent of each other. There is no shared state or context between these two React roots and it's pretty much like running two different React applications on the same page.

Also, after rendering root element with ReactDOM.render into a container node, all other descendant elements will be rendered inside it by React and we don't have any control to change where they get rendered (this will change in the future).

So in your case, if you want to render these two components in different container nodes, you won't be able to have an App component which keeps a shared state or event handling. But instead of that you can create two different React roots and share objects and methods between them via props.

const data = {/*...*/}

ReactDOM.render(<Component data={data} />,
  document.getElementById('component'));

ReactDOM.render(<AnotherComponent data={data} />,
  document.getElementById('anotherComponent'));

However, if you want to change these props at some point you will have to rerender the root component manually. As an example, if you have a counter variable which updates in every second you have to rerender your roots with each new value.

let couter = 0

setInterval(function(){
  counter++

  ReactDOM.render(<Component data={data} />,
    document.getElementById('component'));

  ReactDOM.render(<AnotherComponent data={data} />,
    document.getElementById('anotherComponent'));

}, 1000)

Another good alternative will be using a Redux like state management library. You can have a single store and share it between two roots. I highly recommend this approach if you need to share a very complex state between two roots.

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

// ...

ReactDOM.render(
    <Provider store={store}>
        <Component />
    </Provider>,
    document.getElementById('component')
);

ReactDOM.render(
    <Provider store={store}>
        <AnotherComponent />
    </Provider>,
    document.getElementById('anotherComponent')
);

When you use Redux, you will connect your Component and AnotherComponent to the store with connect higher-order component. Under the hood, this will subscribe your component to store changes and rerender the component when the state is changed using component's forceUpdate method. So you don't have to manually call the ReactDOM.render method as long as you change the state by dispatching actions to the store.

like image 150
Tharaka Wijebandara Avatar answered Oct 01 '22 15:10

Tharaka Wijebandara