JazzCat
JazzCat

Reputation: 4583

React-google-maps re-rendering issue

I'm having some issues with the react-google-maps npm module.

First render, works like a charm. When re-rendering the map-component i get the classic google-maps error.

Uncaught TypeError: Cannot read property 'offsetWidth' of null
Uncaught (in promise) TypeError: Cannot read property 'componentWillReceiveProps' of null(…)

Because the map object isn't available when rendering?

My google-maps Map Component

import React, { PropTypes } from 'react'
import { GoogleMap, Marker, GoogleMapLoader } from 'react-google-maps'
export class Map extends React.Component {
  static propTypes = {
    coordinates: PropTypes.object,
    markers: PropTypes.array
  };

  render () {
    return (<section onloadstyle={{height: '300px'}}>
      <GoogleMapLoader
        containerElement={
          <div
            {...this.props}
            style={{
              height: '300px',
              width: '100%'
            }}
          />
        }
        googleMapElement={
          <GoogleMap
            ref={(map) => console.log(map)}
            defaultZoom={15}
            defaultCenter={this.props.coordinates}>
            {this.props.markers.map((marker, index) => {
              return (
                <Marker key={index} {...marker} />
              )
            })}
          </GoogleMap>
        }
      />
    </section>)
  }
}

export default Map

And i use the component like this:

var coordinates = {lat: this.props.item.delivery_address_lat, lng: this.props.item.delivery_address_lng}
var map = this.props.item.delivery_address_lat !== 0 && this.props.item.delivery_address_lng !== 0 ? (<Row id='map'>
      <Map markers={[{position: coordinates}]} coordinates={coordinates} />
</Row>) : ''

Is this because the google-maps-react module isn't unmounting the component properly or is it something i've done?

The following is inside head

<script src="https://maps.googleapis.com/maps/api/js?key=MY-KEY"></script>

EDIT

Tried to solve it a non react-redux way and this is by no means a solution since it produces the error message: Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op. Please check the code for the Map component.

But still, the map re-renders correctly. I tried doing this the redux way of calling passed prop functions & state and set the {map: section} in the state, passing it down from the calling view. Didn't solve a thing and resulted in the same error message, even though it was delayed with setTimeout

Im kind of stuck here, don't know how to solve this.

componentDidMount () {
    this.setState({map: null})
    setTimeout(() => this.setState({
      map: <section onloadstyle={{height: '300px'}}>
      <GoogleMapLoader
        containerElement={
          <div
            {...this.props}
            style={{
              height: '300px',
              width: '100%'
            }}
          />
        }
        googleMapElement={
          <GoogleMap
            ref={(map) => console.log(map)}
            defaultZoom={15}
            defaultCenter={this.props.coordinates}>
            {this.props.markers.map((marker, index) => {
              return (
                <Marker key={index} {...marker} />
              )
            })}
          </GoogleMap>
        }
      />
    </section>
    }), 300)
  }

  render () {
    if (!this.state) {
      return <span />
    } else {
      return this.state.map
    }
  }

Upvotes: 4

Views: 4886

Answers (1)

JazzCat
JazzCat

Reputation: 4583

The solution for the second edit was to clear the setTimeout() call in the componentWillUnmount() function.

You always have to clear intervals & timeouts when the component is unmounting.

componentDidMount () {
    this.setState({map: null})
    this.timeout = setTimeout(() => this.setState({
      map: <section onloadstyle={{height: '300px'}}>
      <GoogleMapLoader
        containerElement={
          <div
            {...this.props}
            style={{
              height: '300px',
              width: '100%'
            }}
          />
        }
        googleMapElement={
          <GoogleMap
            ref={(map) => console.log(map)}
            defaultZoom={15}
            defaultCenter={this.props.coordinates}>
            {this.props.markers.map((marker, index) => {
              return (
                <Marker key={index} {...marker} />
              )
            })}
          </GoogleMap>
        }
      />
    </section>
    }), 300)
  }

  componentWillUnmount () {
    clearTimeout(this.timeout)
  }

  render () {
    if (!this.state) {
      return <span />
    } else {
      return this.state.map
    }
  }

This solution isn't a good one and isn't in-line with the react-redux workflow. But it works.

Upvotes: 1

Related Questions