在React选项卡组件中管理OpenLayers映射

时间:2017-09-05 03:34:16

标签: javascript reactjs tabs frontend openlayers

我正在使用带有各种标签的导航栏构建SPA应用。选择选项卡后,我会通过redux调度操作,AppBody组件会根据选中的选项卡重新呈现自己(请参阅renderAppBody()中的AppBody)。

我的问题是其中一个标签必须包含OpenLayers地图。我首先要在地图上安装地图时遇到了很多麻烦,因为它必须以DOM上已经存在的元素为目标。我通过覆盖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;

这意味着每当我切换标签时,我的地图元素都会被销毁/删除,并替换为下一个标签的内容。效果是我第一次选择它渲染的地图选项卡,但是如果我然后选择另一个选项卡,然后重新选择地图选项卡,则地图将不会渲染。

我的方法对于我想要的结果本身存在缺陷吗?这是我的第一个较大的React项目,所以我不确定设计这种行为的最佳方法。

我应该:

  • 维护对地图项的引用并在重新渲染时重新加载它? (似乎有问题)
  • 隐藏标签而不是替换它们? (似乎也有问题)
  • 制作MapBody有两种状态:visibleinactive。然后总是将它渲染到屏幕上,并根据其状态(看起来像hacky)将其隐藏起来
  • 更优雅的东西?

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);

谢谢!

1 个答案:

答案 0 :(得分:0)

我最终总是将MapBody组件添加到AppBody,无论选择的标签如何。然后我向active添加了MapBody道具以添加显示/隐藏CSS类。这样,当选项卡发生变化时,地图容器永远不会被删除/重置,因此可以很好地维护状态。我的方法并不特别优雅(读作:它是一个肮脏,肮脏的黑客),但它仍然有效。

我的MapBody渲染功能变为:

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

通过添加以下CSS 主要是给出了所需的行为:

.inactive_map {
   display: none;
}

这会导致在切换选项卡时正确呈现/隐藏地图容器,但地图画布是灰色的,并且不会呈现任何内容。要解决此问题,我会覆盖componentDidUpdate()以调用map.updateSize(),这会强制重新计算地图视口大小。最终代码:

<强> 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>
)