Ich baue eine SPA-App mit einer Navigationsleiste mit verschiedenen Registerkarten. Wenn eine Registerkarte ausgewählt ist, sende ich eine Aktion über Redux, und die Komponente AppBody
gibt sich selbst neu, je nachdem, welche Registerkarte ausgewählt ist (siehe renderAppBody()
in AppBody
).Verwalten einer OpenLayers-Map in einer React-Registerkarte Komponente
Mein Problem ist, dass eine der Registerkarten eine OpenLayers-Map enthalten muss. Ich hatte große Schwierigkeiten, die Karte zuerst zu mounten, da sie auf ein Element abzielen muss, das bereits im DOM existiert. Ich tat dies durch zwingende componentDidMount
:
MapBody.js
import React from 'react';
import "ol/ol.css"
import Map from 'ol/map'
import View from 'ol/view'
import Tile from 'ol/layer/tile'
import OSM from 'ol/source/osm'
import "../../sass/App.scss";
var map = new Map({
layers: [
new Tile({
source: new OSM()
}),
],
view: new View({
center: [0, 0],
zoom: 4
})
});
const MapBody = React.createClass({
render: function() {
return (<div id="map"></div>);
},
componentDidMount: function() {
map.setTarget("map");
}
});
export default MapBody;
Das bedeutet, dass, wenn ich Tabs wechseln, wird meine Karte Element zerstört/entfernt und mit dem Inhalt für das nächste Register ersetzt. Der Effekt ist, dass ich das erste Mal, wenn ich die Map-Registerkarte auswähle, rendere, aber wenn ich dann eine andere Registerkarte auswähle und dann die Map-Registerkarte erneut auswähle, wird die Map nicht gerendert.
Ist mein Ansatz inhärent fehlerhaft für das Ergebnis, das ich möchte? Dies ist mein erstes großes React-Projekt, daher bin ich mir nicht sicher, wie dieses Verhalten am besten zu gestalten ist.
Sollte ich:
- einen Verweis auf das Kartenobjekt pflegen und sie auf rerender reappend? (scheint problematisch)
- Tabs ausblenden anstatt sie zu ersetzen? (scheint auch problematisch)
- Machen MapBody haben zwei Zustände:
visible
undinactive
. Dann render es immer auf dem Bildschirm und versteckt es mit CSS basierend auf seinem Zustand (scheint hacky) - Etwas eleganter?
AppBody.js
import React from 'react';
import { connect } from 'react-redux';
import Activity from '../components/body/Activity'
import CategoryBody from '../components/body/CategoryBody'
import MapBody from '../components/body/MapBody'
import Search from '../components/body/Search'
import tabs from "../actions/tabDefinitions.js"
import "../sass/App.scss";
function renderAppBody(activeTab) {
switch (activeTab) {
case tabs.T_CATEGORIES:
return <CategoryBody />
case tabs.T_MAP:
return (<MapBody />)
case tabs.T_SEARCH:
return <Search />
case tabs.T_ACTIVITY:
return <Activity />
default:
return <div>Oops! Something went wrong :(</div>
}
}
const AppBody = ({activeTab}) => (
<div className="frame_wrapper">
{renderAppBody(activeTab)}
</div>
)
const mapStateToProps = (state) => ({
activeTab: state.activeTab,
});
export default connect(mapStateToProps)(AppBody);
Dank!