2017-09-05 1 views
1

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 und inactive. 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!

Antwort

0

Ich landete immer die MapBody Komponente zu AppBody unabhängig von der ausgewählten Registerkarte. Ich fügte dann eine active Stütze zu MapBody hinzu, um Show Show/hide CSS Klassen hinzuzufügen. Auf diese Weise wird der Kartencontainer nie entfernt/zurückgesetzt, wenn der Tab geändert wird, so dass der Zustand gut erhalten bleibt. Mein Ansatz fühlt sich nicht besonders elegant an (lese: es ist ein dreckiger, schmutziger Hack), aber es funktioniert trotzdem.

Meine MapBody Render-Funktion wurde:

render: function() { 
    return (<div id="map" 
       className={this.props.active ? "active_map" : "inactive_map"}> 
      </div>); 
} 

durch die folgende CSS Hinzufügen meist das gewünschte Verhalten gab:

.inactive_map { 
    display: none; 
} 

Dies ist die Karte Container verursacht richtig/hidden gerendert werden beim Einschalten Tabs, aber der Kartenbereich war grau und zeigte keinen Inhalt. Um dies zu beheben, habe ich die componentDidUpdate() überschrieben, um map.updateSize() aufzurufen, was eine Neuberechnung der Größe des Karten-Viewports erzwingt.Schlusscode:

MapBody.js

const MapBody = React.createClass({ 
    render: function() { 
    return (<div id="map" 
       className={this.props.active ? "active_map" : "inactive_map"}> 
      </div>); 
    }, 
    componentDidMount: function() { 
    this.props.map.setTarget("map"); 
    }, 
    componentDidUpdate: function() { 
    this.props.map.updateSize(); 
    } 
}); 

AppBody.js

function renderAppBody(activeTab) { 
    switch (activeTab) { 
    case tabs.T_CATEGORIES: 
     return <CategoryBody /> 
    case tabs.T_MAP: 
     return ""; 
    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)} 
     <Map active={activeTab == tabs.T_MAP}/> 
    </div> 
) 
Verwandte Themen