如何将ReactJS组件用作Google Maps API Infowindow的内容字符串

时间:2016-09-14 02:07:43

标签: google-maps reactjs infowindow

我有一个在reactJS中使用Google map api的应用程序:

https://github.com/strangebnb/react-airbnb

除了使用ReactJS组件作为Google Map API信息窗口的内容字符串之外,我已成功完成了我需要做的所有事情

我没有使用任何库或npm包来合并2.直接使用Google Maps API和ReactJS。

以下是我将渲染地图的整个组件的代码:

if ( variable != null )

在下面的方法中,我的contentString需要是反应组件,而不是 html或字符串,这是Google API想要的。

import React from 'react'
import ReactDOM from 'react-dom'
import axios from 'axios'
import Navbar from '../navbar/Navbar.js'
import moment from 'moment'
import Rheostat from 'rheostat'
import _ from 'lodash'
import Slider from 'react-slick'
import PrevArrow from './PrevArrow'

import DateRangePickerGmapPage from '../date-range-picker/DateRangePickerGmapPage.jsx';

require('./searchResults.scss');
require('./_datepicker2.scss');

var sliderMin = 0;

export default class SearchResults extends React.Component {

  constructor(props) {
    super(props)

    this.state = {
      zoom: 12,
      iCenter: {
          lng: -90.1056957,
          lat: 29.9717272
      },
      checker: false,
      icon: {
          path: 'M 0,0 20,0 20,16 14,16 10,24 6,16 0,16 z',
          fillColor: '#FF5A5F',
          fillOpacity: 1,
          scale: 1.5,
          strokeColor: 'RGBA(100,100,100,0.5)',
          strokeWeight: 1,
      },
      entireHome: false,
      privateRoom: false,
      sharedRoom: false,
      location: null,
      data: null,
      startDate: null,
      endDate: null,
      numGuests: 1,
      values: [0,100],
      sliderMin: 0,
      sliderMax: 100,
      roomTypeSelected: null,
      picture_urls: [],
      propertyNames: [],
      star_rating: [],
      price_array: []
  }

  axios.get('/getData').then(response => {

      const x = response.data;

      this.setState({
          iCenter: {
            lat: x.center_lat,
            lng: x.center_lng
          },
          location: x.canonical_location_en
      })

      this.setState({
          data: x,
          location: x.location,
          startDate: x.startDate,
          endDate: x.endDate,
          numGuests: x.numGuests,
          sliderMax: x.max_price_total,
          sliderMin: x.min_price_total,
          values: [x.min_price_total, x.max_price_total]
      }, ()=>{
          this.renderMap(x);
      });


  })
}

static propTypes() {
  initialCenter: React.PropTypes.objectOf(React.PropTypes.number).isRequired
}

render = () => {

  var settings = {
    //  prevArrow: {PrevArrow},
     arrows: true,
     infinite: true,
     slidesToShow: 1,
     slidesToScroll: 1,
     speed: 0.0001
   };

let arrOfSliders = [];

if(this.state.picture_urls.length != 0){
  for(let i = 0; i < this.state.picture_urls.length; i++){
   var slider = <div><Slider className='slider' {...settings}>
     <div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][0]} ></img></div>
     <div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][1]} ></img></div>
     <div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][2]} ></img></div>
     <div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][3]} ></img></div>
     <div className='img-container'><img className='slider-img' src={this.state.picture_urls[i][4]} ></img></div>
   </Slider>
     <p className='img-title'>{this.state.propertyNames[i]}</p>
     <p>{this.state.star_rating[i]}</p>
     </div>
     arrOfSliders.push(slider);
     }
     }

     return(
     <div>
       <Navbar/>
       <div className = 'UpdatedText'>
         <p>Current Zoom: {this.state.zoom} </p>
       </div>
       <main className = 'container-search'>
         <div className = 'cards-container'>
           <div className = 'date-panel'>
             <span>Dates</span>
             <DateRangePickerGmapPage location = {this.state.location} renderMap = {this.renderMap.bind(this)} className = 'date-picker'/> </div>
           <div className = 'room-panel'>
             <span> Room Types </span>
             <div className = 'checkboxes'>
               <label>Entire Home</label><input className='checkbox' id='entireHome' type='checkbox' name='Entire home/apt' value={this.state.entireHome} onChange={this.handleRoomTypes}/>
               <label>Private Room</label><input className='checkbox' id='privateRoom' type='checkbox' name='Private room' value={this.state.privateRoom} onChange={this.handleRoomTypes}/>
               <label>Shared Room</label><input className='checkbox' id='sharedRoom' type='checkbox' name='Shared room' value={this.state.sharedRoom} onChange={this.handleRoomTypes}/>
             </div>
           </div>
           <div>
             <Rheostat min={this.state.sliderMin} max={this.state.sliderMax} onValuesUpdated={this.updateValue} values={this.state.values} className = 'rheostat' />
             <ol className='tempVals'>
               <lh>Values</lh>
               {this.state.values.map((value, i) => (
                 <li className='val' key={i}>
                   {this.props.formatValue ? this.props.formatValue(value) : value}
                 </li>
               ))}
             </ol>
           </div>
           <div className='arrayOfSliders'>
             {arrOfSliders.map((slider, i)=>{
               return(
                 <div className='slider-container' key={i}>{slider}</div>
               )
             })}
           </div>
         </div>
         <div className = 'GMap-canvas' ref = "mapCanvas" >  </div>
       </main>
     </div>
     )
     }

     updateValue = (sliderState) => {
       this.setState({
         values: sliderState.values,
       }, this.renderMap(this.state.roomTypeSelected, this.state.values));
     }

     handleRoomTypes = (e) => {

       if (e.target.value === 'false') {
         this.setState({[e.target.id]: true}, ()=>{
           let arr = [this.state.entireHome, this.state.privateRoom, this.state.sharedRoom];
           return this.renderMap(this.convertToNames(arr));
         });
       } else if (e.target.value === 'true') {

         this.setState({[e.target.id]: false}, ()=>{
           let arr = [this.state.entireHome, this.state.privateRoom, this.state.sharedRoom];
           return this.renderMap(this.convertToNames(arr));
         }
         );
       }
     }

     convertToNames = (arr) => {
       var names = ['Entire home/apt', 'Private room', 'Shared room'];

       for(let i = 0; i < arr.length; i++){

         if(arr[i] === false){
           names.splice(i,1);
           arr.splice(i,1);
           i--;
         }
       }

       console.log('names: ', names);
       this.setState({roomTypeSelected: names});
       return names
     }

     componentDidUnMount() {
       google.maps.event.clearListeners(map, 'zoom_changed')
     }

     createMap = () => {
       let mapOptions = {
         zoom: this.state.zoom,
         center: this.mapCenter()
       }
       return new google.maps.Map(this.refs.mapCanvas, mapOptions)
     }

     mapCenter = () => {

       return new google.maps.LatLng(
       this.state.iCenter.lat,
       this.state.iCenter.lng
       )
     }

     createMarker = (lat, lng, price) => {

       var marker = new google.maps.LatLng(
       lat, lng
       );

       return new Marker({
         position: marker,
         map: this.map,
         icon: {
           path: SQUARE_PIN,
           fillOpacity: 0,
           strokeColor: '#9BA198',
           strokeWeight: 0,
         },
         map_icon_label: '<span class=price>$' + price + '</span>'
       })
     }

     createInfoWindow = () => {
       let contentString = `<div>hi</div>`
       return new google.maps.InfoWindow({
         map: this.map,
         anchor: this.marker,
         content: contentString
       })
     }

     handleZoomChange = () => {
       this.setState({
         zoom: this.map.getZoom()
       })
     }

     renderMap = (arr, priceRange = [null,null]) => {

       console.log(arr);

       axios.post('/search',{
         searchVal: this.state.location,
         startDate: this.state.startDate,
         endDate: this.state.endDate,
         numGuests: this.state.numGuests,
         room_types: arr,
         price_min: this.state.sliderMin,
         price_max: this.state.sliderMax,
       }).then(response => {

         const x = response.data;

         let listingsArray = response.data.results_json.search_results;
         this.map = this.createMap()
         this.latlngbounds = new google.maps.LatLngBounds();

         let pics_array = [];
         let propertyNames = [];
         let star_rating = [];
         let price_array = [];

         for (let i = 0; i < listingsArray.length; i++) {

           const lat = listingsArray[i].listing.lat
           const lng = listingsArray[i].listing.lng

           this.marker = this.createMarker(lat, lng, listingsArray[i].pricing_quote.rate.amount)
           this.infoWindow = this.createInfoWindow()
           var myLatLng = new google.maps.LatLng(lat, lng);
           this.latlngbounds.extend(myLatLng);

           pics_array.push(listingsArray[i].listing.picture_urls);
           propertyNames.push(listingsArray[i].listing.name);
           star_rating.push(listingsArray[i].listing.star_rating);
           price_array.push(listingsArray[i].pricing_quote.rate.amount);

           this.setState({picture_urls: pics_array,
             propertyNames: propertyNames,
             star_rating: star_rating,
             price_array: price_array},
            ()=> { console.log('Testing ES6: ', this.state.propertyNames) }
           )
         }

         console.log('max total price:', x.max_price_total)

         if(x.max_price_total === null && x.min_price_total === null){
              const min = Math.min(...price_array);
              const max = Math.max(...price_array);
           this.setState({
             sliderMin: min,
             sliderMax: max,
             values: [min, max]
           })
         }

      this.map.fitBounds(this.latlngbounds);

      this.setState({
        iCenter: {
          lat: x.center_lat,
          lng: x.center_lng
        }
      })

      google.maps.event.addListener(this.map, 'zoom_changed', () => this.handleZoomChange())

    })
  }

}

Infowindows在renderMap方法中与地图和标记一起呈现。有没有解决这个问题,还是我运气不好?

1 个答案:

答案 0 :(得分:2)

你可以尝试

ReactDOMServer.renderToString

https://facebook.github.io/react/docs/top-level-api.html

示例代码可能是

import ReactDOMServer from 'react-dom/server';


createInfoWindow = () => {
   let contentString = ReactDOMServer.renderToString(<YourComponent/>);
   return new google.maps.InfoWindow({
     map: this.map,
     anchor: this.marker,
     content: contentString
   })
 }