2017-10-20 18 views
0

マップにあるマーカーごとに情報ウィンドウを作成する必要があります。マップ上でマーカーを見ることができますが、InfoWindowを取得するためにマーカーをクリックすると、onToggleOpenthis.setState({isOpen: !this.state.isOpen})を参照して、このエラーTypeError: Cannot read property 'isOpen' of undefinedが発生します。代わってreact-google-maps複数のマーカーと情報ウィンドウ

おかげで

componentWillMount() { 
    this.setState({ markers: [], isOpen: false }) 
    } 

componentDidMount() { 
    let list = { restaurants : []} 
    database.ref('..').on('value', .. => { 
      ... 
      }) 
      this.setState({ markers: list.restaurants}); 
     }) 

} 

onToggleOpen(){ 
    this.setState({isOpen: !this.state.isOpen}) 
} 


render() { 
    const MapWithAMarker = compose(
    withProps({ 
     googleMapURL: ..., 
     loadingElement: ..., 
     containerElement: ..., 
     mapElement: ... 
     }), 
     withScriptjs, 
     withGoogleMap 
    )(props => 
     <GoogleMap 
     defaultZoom={17} 
     defaultCenter={{ lat: ..., lng: ... }} 
     > 
      {props.markers.map(marker => (
      <Marker 
       key={marker.name} 
       position={{ lat: marker.latitude, lng: marker.longitude }} 
       onClick={this.onToggleOpen} 
      > 
      {this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}> marker.key </InfoWindow>} 
      </Marker> 
     ))} 


     </GoogleMap> 
    ); 
    return (
     <section id="mapa"> 
      <div class= "container"> 
       <div class="row"> 
        <div class="col-md-12 text-left"> 
         <h2 class="section-heading">MAPA</h2> 

         <MapWithAMarker markers={this.state.markers}/> 

        </div> 
       </div> 
       <div class="row text-center"> 

       </div> 
      </div> 
     </section> 
    ) 
} 

EDIT:更新されたコード:

export default class Mapa extends Component { 
    constructor(props) { 
    super(props) 
    this.state = { 
     markers: [], 
     isOpen: false 
    } 
    } 

componentDidMount() { 
    let list = { restaurants : []} 
    database.ref('..').on('value', restaurants => { 
      restaurants.forEach(restaurant => { 
        list.restaurants.push({'name': restaurant.key, 
          'longitude': restaurant.val().lng, 
          'latitude': restaurant.val().lat} 

         ) 
      }) 
      this.setState({ markers: list.restaurants }); 
     }) 

} 

onToggleOpen =() => { 
     this.setState({isOpen: !this.state.isOpen}) 
    } 

render() { 

    const MapWithAMarker = compose(
    withProps({ 
     googleMapURL: "https://maps.googleapis.com/maps/api/js?key=...&v=3.exp&libraries=geometry,drawing,places", 
     loadingElement: <div style={{ height: `100%` }} />, 
     containerElement: <div style={{ height: `400px` }} />, 
     mapElement: <div style={{ height: `100%` }} /> 
     }), 
     withScriptjs, 
     withGoogleMap 
    )(props => 
     <GoogleMap 
     defaultZoom={17} 
     defaultCenter={{ lat: .., lng: ... }} 
     > 
      {props.markers.map(marker => (
      <Marker 
       key={marker.name} 
       position={{ lat: marker.latitude, lng: marker.longitude }} 
       onClick={this.onToggleOpen} 
      > 
      {this.state.isOpen && <InfoWindow onCloseClick={this.onToggleOpen}> marker.key </InfoWindow>} 
      </Marker> 
     ))} 

     </GoogleMap> 
    ); 
    return (
     <section id="mapa"> 
      <div class= "container"> 
      <h3 class="info-title"><span class="info-title-span">Tasty and Convenient.</span></h3> 
       <div class="row"> 
        <div class="col-md-12 text-left"> 


         <MapWithAMarker markers={this.state.markers}/> 

        </div> 
       </div> 
       <div class="row text-center"> 

       </div> 
      </div> 
     </section> 
    ) 
} 
+0

だけrenderメソッドでこれを宣言し、それがスコープ内にありますので、そこからそれを呼び出す: 'VARいるisOpen = this.state.isOpen;どのように私はそれぞれのプロパティを作ることができる' – fungusanthrax

答えて

3

エラーは、this.state.isOpenを取得しようとしている場所の範囲内でそのthis.state == undefinedを示しています。

これは、this.onToggleOpen()関数の有効範囲がコンポーネントに正しくバインドされていないためです。

onToggleOpen =() => { 
    this.setState({isOpen: !this.state.isOpen}) 
} 

サイドノート:初期this.stateを宣言する

ベストプラクティスそうのようなあなたのコンポーネントのconstructorライフサイクルメソッド内でそうすることである

はそうは次のように矢印の機能を使用するようにリファクタリングしてみ:

constructor(props) { 
    super(props) 
    this.state = { 
    markers: [], 
    isOpen: false 
    } 
} 

また、this.state.isOpenは、すべてのブランケット値ではなく、markersのユニークな特性ですか?一度にすべてではなく、個々のマーカーを個別に開くことができます。

例ソリューション:

// React. 
import React from 'react' 


// Other Dependencies... 


// <Map/>. 
export default class Map extends React.Component { 

    // Constructor. 
    constructor(props) { 

    // Super Props. 
    super(props) 

    // State. 
    this.state = { 
     markers: [] 
    } 
    } 


    // Render. 
    render() { 

    // Map With A Marker. 
    const MapWithAMarker = compose(
     withProps({ 
     googleMapURL: "https://maps.googleapis.com/maps/api/js?key=...&v=3.exp&libraries=geometry,drawing,places", 
     loadingElement: <div style={{ height: `100%` }} />, 
     containerElement: <div style={{ height: `400px` }} />, 
     mapElement: <div style={{ height: `100%` }} /> 
     }), 
     withScriptjs, 
     withGoogleMap 
    )(props => 
     <GoogleMap defaultZoom={17} defaultCenter={{ lat: .., lng: ... }}> 
      {props.markers.map(props => (
      <RestaurantMarker key={props.name} {...props}/> 
     ))} 
     </GoogleMap> 
    ) 

    // Return Map. 
    return (
     <section id="mapa"> 
      <div class= "container"> 
      <h3 class="info-title"><span class="info-title-span">Tasty and Convenient.</span></h3> 
      <div class="row"> 
       <div class="col-md-12 text-left"> 
       <MapWithAMarker markers={this.state.markers}/> 
       </div> 
      </div> 
      <div class="row text-center"> 

      </div> 
      </div> 
     </section> 
    ) 
    } 

    // Did Mount. 
    componentDidMount() { 

    // Download Restaurants. 
    database.ref('..').on('value', restaurants => { 

     // Restaurants Placeholder. 
     let restaurants : [] 

     // Map Restaurants To List. 
     restaurants.forEach((restaurant) => { 
     restaurants.push({ 
      'name': restaurant.key, 
      'longitude': restaurant.val().lng, 
      'latitude': restaurant.val().lat 
     }) 
     }) 

     // Update State. 
     this.setState({ 
     markers: restaurants 
     }) 
    }) 
    } 
} 


// <RestaurantMarker/>. 
class RestaurantMarker extends React.Component { 

    // Constructor. 
    constructor(props) { 

    // Super Props. 
    super(props) 

    // State. 
    this.state = { 
     open: false 
    } 
    } 

    // Render. 
    render() { 


    // Extract Props. 
    const { 
     props: { 
     name, 
     latitude, 
     longitude 
     } 
    } = this 


    // Return Restaurant Marker Component. 
    return (
     <Marker key={name} position={{ lat: latitude, lng: longitude }}> 
     {this.state.open ? (
      <InfoWindow onClick={() => this.setState({open: !this.state.open})}> {name} </InfoWindow> 
     ) : ''} 
     </Marker> 
    ) 
    } 
} 
+0

マーカーの?間違いなく、私はクリックしたマーカーの情報ウィンドウを必要とします。おそらく小道具を使って 'isOpen'を渡しているのでしょうか? –

+0

レンダリング時に、 'this.state.markers'子のそれぞれに対して' isOpen'プロパティをチェックするロジックを挿入します。すなわち、あなたの 'props.markers.map()'関数の中で: 'if(marker.isOpen){//マーカーのオープンバージョンを返します}' –

+0

私はそれを動作させることができませんでした...私は 'isOpen'を'marker.key}'、 '{list.restaurants.push({...、isOpen:false})'とそれ以降は '{marker.isOpen && 'onToggleOpen'関数で何をすべきかわからないので、私はその小道具を変更することができます。 –

関連する問題