2017-12-21 7 views
2

アーキテクチャは次のようになります:plotMapコンポーネントがあり、これは状態からプロットのリストを取得し、plotMarkerコンポーネントにマップします。 /マーカーは、地図のズーム(状態からの読み込み)に基づいています。指定のプロットが編集用に選択されている場合、plotMarkerコンポーネントは編集可能なplotPolygonコンポーネントを返します。ユーザーが編集したplotPolygonコンポーネントを保存すると、状態プロットリストの対応するプロットが更新されます。React Redux - 子コンポーネントが状態変更時に再レンダリングしません

問題:編集されたplotPolygonコンポーネントが正常に保存されるとすぐに表示されるplotMarkerのポリゴンは、新しい図形では更新されず、古い図形は維持されます。 1つがズームアウトし、plotMarkerがマーカコンポーネントをレンダリングしてズームインし、plotMarkerが再びポリゴンコンポーネントをレンダリングする場合にのみ、新しいシェイプが表示されます。

これはアプリの中での遅れのためでしょうか? plotMarkerが正常に保存されるとすぐに新しいポリゴンを表示させるにはどうすればよいですか?

plotMap成分

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../../actions'; 
import { Map, TileLayer, LayersControl, MapControl } from 'react-leaflet'; 
import { GoogleLayer } from './GoogleLayer'; 
import { geolocated } from 'react-geolocated'; 
import 'leaflet-geocoder-mapzen'; 
import SearchBox from './searchBox'; 
import Control from 'react-leaflet-control'; 
import { centroid } from '@turf/turf'; 
import PlotMarker from './plotMarker'; 

const { BaseLayer } = LayersControl; 
const key = 'key'; 
const hybrid = 'HYBRID'; 
const terrain = 'TERRAIN'; 
const road = 'ROADMAP'; 
const satellite = 'SATELLITE'; 

const centerLat = props => { 
    if (
     props.isGeolocationAvailable && 
     props.isGeolocationEnabled && 
     props.coords 
    ) { 
     return props.coords.latitude; 
    } 
    return 32.11; 
}; 

const centerLong = props => { 
    if (
     props.isGeolocationAvailable && 
     props.isGeolocationEnabled && 
     props.coords 
    ) { 
     return props.coords.longitude; 
    } 
    return 34.963; 
}; 

const mapCenterPoint = props => { 
    if (props.plots && (props.selectedPlot || props.plotBeingEdited)) { 
     let ourPlot = props.plots.filter(
      plot => plot._id === (props.selectedPlot || props.plotBeingEdited) 
     )[0]; 
     try { 
      let center = centroid(ourPlot.feature).geometry.coordinates.reverse(); 
      return { center: center, zoom: 16 }; 
     } catch (e) { 
      console.log(e); 
     } 
    } 
    return { center: [centerLat(props), centerLong(props)], zoom: 8 }; 
}; 

export class PlotMap extends Component { 
    markers = props => { 
     if (props.plots) { 
      return (
       <div> 
        {(props.filteredPlots || props.plots).map(
         plot => 
          plot && 
          plot.feature && 
          plot._id && (
           <PlotMarker 
            key={plot._id} 
            id={plot._id} 
            name={plot.name} 
            geoJSON={plot.feature} 
           /> 
          ) 
        )} 
       </div> 
      ); 
     } 
    }; 

    render() { 
     return (
      <div 
       className="col-sm-8 m-auto p-0 flex-column float-right" 
       style={{ height: `85vh` }}> 
       <Map 
        center={mapCenterPoint(this.props).center} 
        zoom={mapCenterPoint(this.props).zoom} 
        zoomControl={true} 
        onZoomend={e => { 
         this.props.setZoomLevel(e.target.getZoom()); 
        }} 
        onMoveEnd={e => { 
         this.props.setMapCenter(e.target.getCenter()); 
        }}> 
        <LayersControl position="topright"> 
         <BaseLayer name="Google Maps Roads"> 
          <GoogleLayer googlekey={key} maptype={road} /> 
         </BaseLayer> 
         <BaseLayer name="Google Maps Terrain"> 
          <GoogleLayer googlekey={key} maptype={terrain} /> 
         </BaseLayer> 
         <BaseLayer checked name="Google Maps Hybrid"> 
          <GoogleLayer 
           googlekey={key} 
           maptype={hybrid} 
           libraries={['geometry', 'places']} 
          /> 
         </BaseLayer> 
        </LayersControl> 
        <SearchBox postion="bottomright" /> 
        {this.markers(this.props)} 
       </Map> 
      </div> 
     ); 
    } 
} 

function mapStateToProps(state) { 
    return { 
     filteredPlots: state.plots.filteredPlots, 
     plots: state.plots.plots, 
     selectedPlot: state.plots.selectedPlot, 
     mapCenter: state.plots.mapCenter 
    }; 
} 

export default geolocated({ 
    positionOptions: { 
     enableHighAccuracy: false 
    }, 
    userDecisionTimeout: 5000, 
    suppressLocationOnMount: false 
})(connect(mapStateToProps, actions)(PlotMap)); 

plotMarker成分:

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../../actions'; 
import { Marker, Popup, GeoJSON } from 'react-leaflet'; 
import { centroid } from '@turf/turf'; 
import PlotPolygon from './plotPolygon'; 

const position = geoJSON => { 
    return centroid(geoJSON).geometry.coordinates.reverse(); 
}; 

export class PlotMarker extends Component { 
    render() { 
     const { 
      id, 
      name, 
      geoJSON, 
      zoomLevel, 
      selectedPlot, 
      plotBeingEdited 
     } = this.props; 
     const markerPosition = position(geoJSON); 
     let style =() => { 
      return { 
       color: 'blue' 
      }; 
     }; 
     if (selectedPlot === id) { 
      style =() => { 
       return { 
        color: 'red' 
       }; 
      }; 
     } 
     if (zoomLevel > 14 && plotBeingEdited === id) { 
      return <PlotPolygon id={id} geoJSON={geoJSON} />; 
     } else if (zoomLevel > 14) { 
      return (
       <GeoJSON 
        id={id} 
        data={geoJSON} 
        style={style} 
        onClick={() => { 
         this.props.selectPlot(id); 
        }} 
       /> 
      ); 
     } 
     return (
      <Marker 
       id={id} 
       className="marker" 
       position={markerPosition} 
       onClick={() => { 
        this.props.selectPlot(id); 
       }}> 
       <Popup> 
        <span>{name}</span> 
       </Popup> 
      </Marker> 
     ); 
    } 
} 

function mapStateToProps(state) { 
    return { 
     selectedPlot: state.plots.selectedPlot, 
     plotBeingEdited: state.plots.plotBeingEdited, 
     zoomLevel: state.plots.zoomLevel, 
     plots: state.plots.plots, 
     filteredPlots: state.plots.filteredPlots 
    }; 
} 

export default connect(mapStateToProps, actions)(PlotMarker); 

plotPolygon成分

import React, { Component } from 'react'; 
import { connect } from 'react-redux'; 
import * as actions from '../../actions'; 
import { Polygon, FeatureGroup } from 'react-leaflet'; 
import { EditControl } from 'react-leaflet-draw'; 

const positions = props => { 
    return props.geoJSON.geometry.coordinates[0].map(a => [a[1], a[0]]); 
}; 

export class PlotPolygon extends Component { 
    render() { 
     const { id, geoJSON } = this.props; 
     return (
      <FeatureGroup> 
       <EditControl 
        position="topright" 
        onEdited={e => { 
         e.layers.eachLayer(a => { 
          this.props.updatePlot({ 
           id: id, 
           feature: a.toGeoJSON() 
          }); 
         }); 
        }} 
        edit={{ remove: false }} 
        draw={{ 
         marker: false, 
         circle: false, 
         rectangle: false, 
         polygon: false, 
         polyline: false 
        }} 
       /> 
       <Polygon positions={[positions(this.props)]} />; 
      </FeatureGroup> 
     ); 
    } 
} 

function mapStateToProps(state) { 
    return { plots: state.plots.plots, filteredPlots: state.plots.filteredPlots }; 
} 

export default connect(mapStateToProps, actions)(PlotPolygon); 
+1

あなたが編集モードを終了した後、あなたのズームレベルをリセットする必要がありますか?あなたのロジックは 'mapCenterPoint'とplotMarkerの' if(zoomLevel ... ')部分の間に非常に強く結びついていますが、編集後(そして手動でズームするまで)常にtrueと評価される状態になっているのではないか、 : 'props.plots &&(props.selectedPlot || props.plotBeingEdited)' –

+1

うん、それはうまくいく。私が思いついたハッキーなやり方よりももっとエレガントなやり方を見つけなければならない。 、それから15の、アクションの成功を保存した直後)、それは動作します。あなたは答えとしてコメントを入れることができますか? –

答えて

2

元の解決策:

編集モードを終了した後にズームレベルをリセットする必要がありますか?あなたのロジックは、mapCenterPointif(zoomLevel...部分の間に非常に密接に結合されています。plotMarkerです。より多くを把握するために

:リファクタリングのprops.plots && (props.selectedPlot || props.plotBeingEdited)


思考:あなたは常に編集(および手動ズームまで)の後に真の評価にこれを引き起こしている状態を有することができる場合、私は思ったんだけどエレガントな方法

オプション1:HOCs

高次コンポーネント(またはHOCs)

は、このために偉大なアプローチであるかもしれません。

export default connect(mapStateToProps, actions)(PlotMarker); 

HOCは本当にリアクトワールドで役に立つものを返す関数です。したがって、これらはコードの再利用の素晴らしい形式です。 connectは、このシナリオでは関数を返すHOCですが、コンポーネントを返すためにHOCがよく使用されます。そのため、ロジック自体を実行してレンダリングするマーカーコンポーネントのタイプを決定するようなplotMarker(zoomLevel, beingEdited)のようなHOCを持つことができます。

さらに詳しくはReact's Higher Order Component Documentationをご覧ください。


オプション2:シングルreturn文

私はいつもrenderメソッドのための単一のreturn文を使用してのファンしてきました。私は、Reactがどのように処理するのかを深く掘り下げたわけではありませんが、私の経験からこのように反応していることは間違いないと思うので、ズームレベルを変えてリセットする必要はありません。

私は1つのリターン内PlotMarkerのロジックのすべてを実行することになり方法:

export class PlotMarker extends Component{ 
    render(){ 
    const { 
     id, 
     name, 
     geoJSON, 
     zoomLevel, 
     selectedPlot, 
     plotBeingEdited 
    } = this.props; 

    const markerPosition = position(geoJSON); 

    let style =() =>{ 
     return { 
     color: 'blue' 
     }; 
    }; 
    if(selectedPlot === id){ 
     style =() =>{ 
     return { 
      color: 'red' 
     }; 
     }; 
    } 

    return (
     <div> 
     { 
      zoomLevel > 14 && plotBeingEdited === id && 
      <PlotPolygon id={id} geoJSON={geoJSON}/> || 

      zoomLevel > 14 && 
      <GeoJSON 
      id={id} 
      data={geoJSON} 
      style={style} 
      onClick={() =>{ 
       this.props.selectPlot(id); 
      }} 
      /> || 

      <Marker 
      id={id} 
      className="marker" 
      position={markerPosition} 
      onClick={() => { 
       this.props.selectPlot(id); 
      }}> 
      <Popup> 
       <span>{name}</span> 
      </Popup> 
      </Marker> 
     } 
     </div> 
    ); 
    } 
} 
関連する問題