title: How to use a ReactJS component as content string for Google Maps API Infowindow
body: <p>I have an app that uses Google map api inside reactJS:</p>
  
  <p><a href="https://github.com/strangebnb/react-airbnb" rel="nofollow">https://github.com/strangebnb/react-airbnb</a></p>
  
  <p>I've been successfully able to do everything I need to do except using a ReactJS component as the content string for a Google Map API infowindow</p>
  
  <p>I am not using any libraries or npm packages to merge the 2. Just straight Google Maps API and ReactJS.</p>
  
  <p>Here is my code for the entire component that will render the map: </p>
  
  <pre><code>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 =&gt; {
  
        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]
        }, ()=&gt;{
            this.renderMap(x);
        });
  
  
    })
  }
  
  static propTypes() {
    initialCenter: React.PropTypes.objectOf(React.PropTypes.number).isRequired
  }
  
  render = () =&gt; {
  
    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 &lt; this.state.picture_urls.length; i++){
     var slider = &lt;div&gt;&lt;Slider className='slider' {...settings}&gt;
       &lt;div className='img-container'&gt;&lt;img className='slider-img' src={this.state.picture_urls[i][0]} &gt;&lt;/img&gt;&lt;/div&gt;
       &lt;div className='img-container'&gt;&lt;img className='slider-img' src={this.state.picture_urls[i][1]} &gt;&lt;/img&gt;&lt;/div&gt;
       &lt;div className='img-container'&gt;&lt;img className='slider-img' src={this.state.picture_urls[i][2]} &gt;&lt;/img&gt;&lt;/div&gt;
       &lt;div className='img-container'&gt;&lt;img className='slider-img' src={this.state.picture_urls[i][3]} &gt;&lt;/img&gt;&lt;/div&gt;
       &lt;div className='img-container'&gt;&lt;img className='slider-img' src={this.state.picture_urls[i][4]} &gt;&lt;/img&gt;&lt;/div&gt;
     &lt;/Slider&gt;
       &lt;p className='img-title'&gt;{this.state.propertyNames[i]}&lt;/p&gt;
       &lt;p&gt;{this.state.star_rating[i]}&lt;/p&gt;
       &lt;/div&gt;
       arrOfSliders.push(slider);
       }
       }
  
       return(
       &lt;div&gt;
         &lt;Navbar/&gt;
         &lt;div className = 'UpdatedText'&gt;
           &lt;p&gt;Current Zoom: {this.state.zoom} &lt;/p&gt;
         &lt;/div&gt;
         &lt;main className = 'container-search'&gt;
           &lt;div className = 'cards-container'&gt;
             &lt;div className = 'date-panel'&gt;
               &lt;span&gt;Dates&lt;/span&gt;
               &lt;DateRangePickerGmapPage location = {this.state.location} renderMap = {this.renderMap.bind(this)} className = 'date-picker'/&gt; &lt;/div&gt;
             &lt;div className = 'room-panel'&gt;
               &lt;span&gt; Room Types &lt;/span&gt;
               &lt;div className = 'checkboxes'&gt;
                 &lt;label&gt;Entire Home&lt;/label&gt;&lt;input className='checkbox' id='entireHome' type='checkbox' name='Entire home/apt' value={this.state.entireHome} onChange={this.handleRoomTypes}/&gt;
                 &lt;label&gt;Private Room&lt;/label&gt;&lt;input className='checkbox' id='privateRoom' type='checkbox' name='Private room' value={this.state.privateRoom} onChange={this.handleRoomTypes}/&gt;
                 &lt;label&gt;Shared Room&lt;/label&gt;&lt;input className='checkbox' id='sharedRoom' type='checkbox' name='Shared room' value={this.state.sharedRoom} onChange={this.handleRoomTypes}/&gt;
               &lt;/div&gt;
             &lt;/div&gt;
             &lt;div&gt;
               &lt;Rheostat min={this.state.sliderMin} max={this.state.sliderMax} onValuesUpdated={this.updateValue} values={this.state.values} className = 'rheostat' /&gt;
               &lt;ol className='tempVals'&gt;
                 &lt;lh&gt;Values&lt;/lh&gt;
                 {this.state.values.map((value, i) =&gt; (
                   &lt;li className='val' key={i}&gt;
                     {this.props.formatValue ? this.props.formatValue(value) : value}
                   &lt;/li&gt;
                 ))}
               &lt;/ol&gt;
             &lt;/div&gt;
             &lt;div className='arrayOfSliders'&gt;
               {arrOfSliders.map((slider, i)=&gt;{
                 return(
                   &lt;div className='slider-container' key={i}&gt;{slider}&lt;/div&gt;
                 )
               })}
             &lt;/div&gt;
           &lt;/div&gt;
           &lt;div className = 'GMap-canvas' ref = "mapCanvas" &gt;  &lt;/div&gt;
         &lt;/main&gt;
       &lt;/div&gt;
       )
       }
  
       updateValue = (sliderState) =&gt; {
         this.setState({
           values: sliderState.values,
         }, this.renderMap(this.state.roomTypeSelected, this.state.values));
       }
  
       handleRoomTypes = (e) =&gt; {
  
         if (e.target.value === 'false') {
           this.setState({[e.target.id]: true}, ()=&gt;{
             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}, ()=&gt;{
             let arr = [this.state.entireHome, this.state.privateRoom, this.state.sharedRoom];
             return this.renderMap(this.convertToNames(arr));
           }
           );
         }
       }
  
       convertToNames = (arr) =&gt; {
         var names = ['Entire home/apt', 'Private room', 'Shared room'];
  
         for(let i = 0; i &lt; 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 = () =&gt; {
         let mapOptions = {
           zoom: this.state.zoom,
           center: this.mapCenter()
         }
         return new google.maps.Map(this.refs.mapCanvas, mapOptions)
       }
  
       mapCenter = () =&gt; {
  
         return new google.maps.LatLng(
         this.state.iCenter.lat,
         this.state.iCenter.lng
         )
       }
  
       createMarker = (lat, lng, price) =&gt; {
  
         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: '&lt;span class=price&gt;$' + price + '&lt;/span&gt;'
         })
       }
  
       createInfoWindow = () =&gt; {
         let contentString = `&lt;div&gt;hi&lt;/div&gt;`
         return new google.maps.InfoWindow({
           map: this.map,
           anchor: this.marker,
           content: contentString
         })
       }
  
       handleZoomChange = () =&gt; {
         this.setState({
           zoom: this.map.getZoom()
         })
       }
  
       renderMap = (arr, priceRange = [null,null]) =&gt; {
  
         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 =&gt; {
  
           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 &lt; 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},
              ()=&gt; { console.log('Testing ES6: ', this.state.propertyNames) }
             )
           }
  
           console.log('max total price:', x.max_price_total)
  
           if(x.max_price_total === null &amp;&amp; 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', () =&gt; this.handleZoomChange())
  
      })
    }
  
  }
  </code></pre>
  
  <p>In the method below, my contentString needs to be a <strong>react component</strong> instead <strong>html or a string</strong>, which is what Google API wants. </p>
  
  <pre><code>createInfoWindow = () =&gt; {
         let contentString = `&lt;div&gt;hi&lt;/div&gt;`
         return new google.maps.InfoWindow({
           map: this.map,
           anchor: this.marker,
           content: contentString
         })
       }
  </code></pre>
  
  <p>Infowindows are rendered in the renderMap method, along with the map and markers. Is there a work around this or am I sore out of luck?</p>