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.
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?
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.
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.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With