2017-10-20 14 views
0

Je dois créer une fenêtre d'information pour chaque marqueur de ma carte. Je peux voir les marqueurs sur la carte, mais quand je clique sur le marqueur pour obtenir l'InfoWindow, j'obtiens cette erreur TypeError: Cannot read property 'isOpen' of undefined, en référence à this.setState({isOpen: !this.state.isOpen}) dans le onToggleOpen.react-google-maps Marqueurs multiples et fenêtre d'information

Merci au nom

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: Code Mise à jour:

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

déclare ceci dans le même render et l'appeler à partir de là il est donc portée: 'var isOpen = this.state.isOpen;' – fungusanthrax

Répondre

3

L'erreur indique que this.state == undefined dans le cadre de l'endroit où vous essayez de récupérer this.state.isOpen. Ceci est dû au fait que la portée de la fonction this.onToggleOpen() n'est pas correctement liée à votre composant.

Essayez refactorisation à utiliser une fonction de flèche comme ceci:

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

Side note:

Les meilleures pratiques de déclarer initiale this.state est de le faire dans constructor méthode du cycle de vie de votre composant comme si :

De même, devrait être this.state.isOpen être une propriété unique pour chacun de vos markers au lieu d'une valeur de couverture pour chacun d'eux? Alors que vous pouvez ouvrir chaque marqueur individuellement, au lieu de tous à la fois.

Exemple Solution:

// 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

Comment pourrais-je faire une propriété pour chaque des marqueurs? Certainement je veux juste la fenêtre d'information pour le marqueur que j'ai cliqué .. Peut-être passer le 'isOpen' à travers les accessoires? –

+0

Je voudrais insérer une logique pour vérifier une propriété 'isOpen' pour chacun des enfants' this.state.markers' lors du rendu. c'est à dire. dans votre fonction 'props.markers.map()': 'if (marker.isOpen) {// renvoie la version ouverte du marqueur}' –

+0

Je ne pouvais pas le faire fonctionner ... J'ai essayé d'ajouter 'isOpen' dans le 'list.restaurants.push ({..., isOpen: false})' et plus tard '{marker.isOpen && marker.key}', mais je Je ne sais pas quoi faire sur la fonction 'onToggleOpen' donc je peux changer les accessoires ... –