Skip to content

Commit

Permalink
feat(async/withScriptjs): provide HOC for loading googleMapURL with…
Browse files Browse the repository at this point in the history
… `scriptjs`

* `withScriptjs` requires a prop: `googleMapURL`
* `withScriptjs` requires a prop: `loadingElement`

BREAKING CHANGE: Apply `withScriptjs` HOC before `withGoogleMaps` HOC.

Before:

```js
<ScriptjsLoader
  hostname={"maps.googleapis.com"}
  pathname={"/maps/api/js"}
  query={{v: `3.${ AsyncGettingStarted.version }`, libraries: "geometry,drawing,places"}}
  loadingElement={
    <div {...this.props} style={{ height: "100%" }}>
      <FaSpinner />
    </div>
  }
  containerElement={
    <div {...this.props} style={{ height: "100%" }} />
  }
  googleMapElement={
    <GoogleMap
      ref={googleMap => {
        googleMap && console.log(`Zoom: ${ googleMap.getZoom() }`);
      }}
      defaultZoom={3}
      defaultCenter={{lat: -25.363882, lng: 131.044922}}
      onClick={::this.handleMapClick}
    >
      <Marker
        {...this.state.marker}
        onRightclick={this.handleMarkerRightclick}
      />
    </GoogleMap>
  }
/>
```

After:

```js
// Wrap all `react-google-maps` components with `withGoogleMap` HOC
// then wraps it into `withScriptjs` HOC
// It loads Google Maps JavaScript API v3 for you asynchronously.
// Name the component AsyncGettingStartedExampleGoogleMap
const AsyncGettingStartedExampleGoogleMap = withScriptjs(
  withGoogleMap(
    props => (
    <GoogleMap
      ref={props.onMapLoad}
      defaultZoom={3}
      defaultCenter={{ lat: -25.363882, lng: 131.044922 }}
      onClick={props.onMapClick}
    >
      {props.markers.map(marker => (
        <Marker
          {...marker}
          onRightClick={() => props.onMarkerRightClick(marker)}
        />
      ))}
    </GoogleMap>
  )
);
// Then, render it:
render(
  <GettingStartedGoogleMap
    googleMapURL="https://maps.googleapis.com/maps/api/js?v=3.exp"
    loadingElement={
      <div style={{ height: `100%` }}>
        <FaSpinner
          style={{
            display: `block`,
            width: `80px`,
            height: `80px`,
            margin: `150px auto`,
            animation: `fa-spin 2s infinite linear`,
          }}
        />
      </div>
    }
    containerElement={
      <div style={{ height: `100%` }} />
    }
    mapElement={
      <div style={{ height: `100%` }} />
    }
    onMapLoad={_.noop}
    onMapClick={_.noop}
    markers={markers}
    onMarkerRightClick={_.noop}
  />,
  document.getElementById('root')
);
```
  • Loading branch information
tomchentw committed Oct 4, 2016
1 parent f61724c commit 14d9273
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 220 deletions.
56 changes: 0 additions & 56 deletions src/lib/async/ScriptjsGoogleMap.js

This file was deleted.

130 changes: 0 additions & 130 deletions src/lib/async/ScriptjsLoader.js

This file was deleted.

98 changes: 98 additions & 0 deletions src/lib/async/withScriptjs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import _ from "lodash";

import invariant from "invariant";

import canUseDOM from "can-use-dom";

import getDisplayName from "react-display-name";

import {
default as React,
PropTypes,
Component,
} from "react";

const LOAIDNG_STATE_NONE = `NONE`;
const LOAIDNG_STATE_BEGIN = `BEGIN`;
const LOAIDNG_STATE_LOADED = `LOADED`;

export default function withScriptjs(WrappedComponent) {
return class Container extends Component {
static displayName = `withScriptjs(${getDisplayName(WrappedComponent)})`;

static propTypes = {
loadingElement: PropTypes.node.isRequired,
googleMapURL: PropTypes.string.isRequired,
};

state = {
loadingState: LOAIDNG_STATE_NONE,
};

isUnmounted = false;

handleLoaded = this.handleLoaded.bind(this);

handleLoaded() {
if (this.isUnmounted) {
return;
}
this.setState({
loadingState: LOAIDNG_STATE_LOADED,
});
}

componentWillMount() {
const {
loadingElement,
googleMapURL,
} = this.props;
invariant(!!loadingElement && !!googleMapURL,
`Required props loadingElement or googleMapURL is missing. You need to provide both of them.`
);
}

componentDidMount() {
const {
loadingState,
} = this.state;
if (loadingState !== LOAIDNG_STATE_NONE || !canUseDOM) {
return;
}
this.setState({
loadingState: LOAIDNG_STATE_BEGIN,
});
// Don't load scriptjs as dependency since we want this module be used on server side.
// eslint-disable-next-line global-require
const scriptjs = require(`scriptjs`);
const {
googleMapURL,
} = this.props;
scriptjs(googleMapURL, this.handleLoaded);
}

componentWillUnmount() {
this.isUnmounted = true;
}

render() {
const {
loadingElement,
googleMapURL, // eslint-disable-line no-unused-vars
...restProps,
} = this.props;

const {
loadingState,
} = this.state;

if (loadingState === LOAIDNG_STATE_LOADED) {
return (
<WrappedComponent {...restProps} />
);
} else {
return loadingElement;
}
}
};
}
34 changes: 0 additions & 34 deletions src/lib/utils/makeUrl.js

This file was deleted.

1 comment on commit 14d9273

@tomchentw
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in the commit message. It should be:

-  <GettingStartedGoogleMap
+  <AsyncGettingStartedExampleGoogleMap

See: a144259

Please sign in to comment.