What is causing my component to unmount? - reactjs

I'm making an app where I have an Overlay component and a Map component rendering behind it just like this:
<div>
{showOverlay && <Overlay />}
<Map /> // this component should mount once
</div>
The overlay is shown to let the map load underneath but when I remove the Overlay (set showOverlay to false here) the Map component re-load.
At first I thought the Map component was just re-rendering, but after some digging I discovered that the component was actually re-mounting.
If I log in the componentWillMount, componentWillUnmount and render methods, the log appear in that order (which seems contradictory)
render
willUnmount
willMount
The parent does not re-mount, only the Map component do.
The Map component just render a div that reference a mapbox-gl-js map (like this https://gist.github.com/tristen/5c4b346ae38892f732504e6785d87057#file-map-js)
What can cause my component to re-mount itself like that ?
Thanks !

Related

How to force one react component to not re-render?

I have a main react component (The entire page) that contains several other UI items in it. One of those UI items is an OpenLayers map. Another component is a text field that contains the latitude and longitude of the current mouse pointer position.
I want the text field to update whenever the mouse pointer moves on the map. In my code's current state, this works.
The problem is every time the mouse moves and I update the react state value for the latitude/longitude (which gets rendered in the text field as expected) the map re-renders. This looks terrible because the map flashes every time as it begins to load the map tiles.
So I have the mouse latitude/longitude position, but I can't get the map to not flash/stutter/strobe.
Is there a way to get a mouse event from the map component, and send it to another component on the same screen without causing the render method to redraw the map every time? Or is React the wrong tool for this project?
As a note, I'm using React Redux to handle some state values, such as the map object. All of my child components are React functional components, but the main component for the page is a React class component.
If it helps, I set the mouse listener on the map like this:
this.props.map.on('pointermove', event => {
this.setState({
mouseCoordinates: (event.coordinate),
});
});
This is my render method:
render() {
return (
<div className="main">
<p className={noMargPad}>
{this.state.mouseCoordinates}
</p>
<Map
center={fromLonLat(this.state.center)}
zoom={this.state.zoom}
>
<Layers>
<TileLayer source={osm()} zIndex={0} />
{this.state.showLayer1 && (
<VectorLayer
source={vector({
features: new GeoJSON().readFeatures(geojsonObject, {
featureProjection: get("EPSG:3857"),
}),
})}
style={FeatureStyles.MultiPolygon}
/>
)}
{this.state.showMarker && (
<VectorLayer source={vector({
features: this.state.features
})} />
)}
</Layers>
<Controls>
<FullScreenControl />
</Controls>
</Map>
</div>
);
}
One of the main advantages of using a tool like React is it will only refresh the components in the render method that have had an update to their dependent data. See this article for more information.
The fact that your map is rendering again indicates that the map, or one of its children is being passed a piece of data that keeps changing.
Based on your code, one possibility is the call to OSM(), since that's a constructor from the OpenLayers API. A new object/class instance in JavaScript could cause data re-render.

Render Map child from outside MapContainer

I would like to render a child inside <MapContainer> from outside the initial MapContainer. Is this possible somehow?
In react-leaflet-v3 I render a lot of items on the map by passing the map object via a reference. But for my current situation I wold like to render a react button on top of the map based on routing.
One way of doing this is to add nest <Route />. inside the MapContainer. This however is not ideal because of the scattered route behaviour...
Is it possible in another way?
I used the portal way to solve my problem:
In my map-container, this is happening:
const [control, setControl] = useState(null);
const handleRef = useCallback((instance) => setControl(instance), [
setControl,
]);
...
<MapContainer ...>
...
<div className="mapcontrol-top-left" ref={handleRef}></div>
</MapContainer>
In a totally different component, where conditionally I want to show something on the Map, I do this (using Material-UI Portal & Fab component):
<Portal container={props.control}>
<Fab size="medium">
<EditIcon />
</Fab>
</Portal>
The material-ui Portal component is easy to use and adds convenience, but a native React Portal will also do the trick...

ReactDOM.render does not update containers props

I have a container containing some html with a <div id="ID"></div>. I have a react stateful component that I want to render in that div using
React.render(<ChildComponent data={this.props.data} />, document.getElementById('ID'))
When I call an action in childcomponent and udate the redux state, the props of the parent container do not update, only the ChildComponent re-renders with old values. Those props get updated when I refresh the page.
What is the solution to this ? Is there any other way to render React component in html so that the props can be updated with new props ?
Can you share your code for <ChildComponent> and its parent? There are a number of things you might be doing wrong but the thing that stands out is that it looks like you're rendering separately from its parent instead of as a child "prop" of its parent, like so:
<ParentComponent>
<ChildComponent />
</ParentComponent>
The official docs also have a lot of examples on how to get started: https://facebook.github.io/react/docs/hello-world.html
Hope this helps!

Avoid `OverlayTrigger` from unmounting overlay

How do I stop the OverlayTrigger component from react-bootstrap from unmounting its overlay component when the onHide prop is called? This is the component that shows the Popover. It is not an issue with Popover since setting overlay={<ComplexComponent />} causes the same issue where ComplexComponent is mounted every time the OverlayTrigger is triggered.
This is a simplified version of what I'm attempting:
const overlay = (<Popover id="some-random-id">
<ComplexComponent />
</Popover>;
<OverlayTrigger
trigger={['hover', 'focus']}
placement="top"
overlay={overlay}
>
<span>trigger label</span>
</OverlayTrigger>
The reason I need to just hide the overlay instead of unmounting it is that ComplexComponent makes service calls on componentWillMount and takes a considerable amount of time to do that initial fetch. I've considered using refs but haven't come up with a good enough strategy.

React js: component is not unmounted properly

We have following scenario:
1. Parent component has child components.
==============================================================
<ContainerComponent>
<Layout>
<CustomComponent>
<ActualComponent>
<CustomComponent>
<ActualComponent>
==============================================================
This way component mounting takes place, and each ContainerComponent rendered according to task.
Component Container contain :
return (
<div className='row' >
<div className='col-md-12' >
<div className="ic-component" id="MainComponent" >
<div style={{'border':'5px;solid #e0e7f0'}}>
<div id="rootwizard3" className='wizard'>
<ul>
{TabHeader}
</ul>
<div className="tab-content" id="tabcontent" >
</div>
</div>
</div>
</div>
</div>
</div>
);
Then ContainerComponent contain Layout component :
$("#tabcontent").empty();
if(LayOut===null)
{
}
else {
React.render(
<div id={tabid}><div id={layoutid}>
<LayOut CurrentStepId={CurrentStepId} TaskDetails={TaskDetails} IsActualComponent="true"/>
</div>
</div>,document.getElementById('tabcontent'));
}
},
Layout component contains CustomComponent :
var findDiv1=$("div > #"+TabbId+" > div > div > div > div > div")[0];
$(findDiv1).empty();
var valueP3=1;
React.render(<CustomComponent inputType={Set} ItemName="" ItemId="" KeyValue={valueP3} addbtndispaly="" editbtndispaly="" deletebtndispaly="" Views="" />,findDiv1);
Unmounting of Container page:
React.unmountComponentAtNode(document.getElementById('tabcontent'));
Following way the components get mounted.
Initial component mounting. Here layout component loaded into Container Component. but custom component is not showing under Layout ? but output is poperly showing.
chrome react tool component loading structure
Second time component mounting, but here it only remove component under "ctab137". not unmounting custom component . Second copy of cutom component get created.
chrome react tool component loading structure-Second time loading
When we go to task(functionality) it mounts parent component and accordingly
respective child component gets mounted.
When we click to another task mean containerComponent then only containerComponent unmount get called. for that we are clearing container componenet div where its child componenet get mounted. and load another task child componenet.
But here is we are facing problem when we mount child componenet every times it get mounted separately if that component is already present. and that create problem. Here is above mentioned custom component is not get propely unmounted. Every time separate customComponent copy is created and that times that funtionality get executed.
Also here is child componenets componentWillUnmount not get called.
I want to know answers of following questions .
How to unmount child components if it is not unmounted ?
How to call child components unmount method if it's not called ?
Is there any way to unmount component by component name ?

Resources