diff --git a/.flowconfig b/.flowconfig index dfcedfa..91878cc 100644 --- a/.flowconfig +++ b/.flowconfig @@ -2,10 +2,7 @@ .*/coverage/.* .*/scripts/.* .*/node_modules/flow-bin/.* -# .*/node_modules/fbjs/.* -.*/node_modules/fbjs/lib/Deferred.js.flow .*/node_modules/.*/flow-bin.*/.* -.*/node_modules/.*/fbjs.*/.* .*/node_modules/.*/broken.json .*/node_modules/fixed-data-table/* .*/node_modules/.*/fixtures/package.json diff --git a/package.json b/package.json index 70bd1a9..c5c17fa 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "dependencies": { "@mapbox/point-geometry": "^0.1.0", "eventemitter3": "^1.1.0", - "fbjs": "^0.8.3", "scriptjs": "^2.5.7" }, "devDependencies": { diff --git a/src/google_map.js b/src/google_map.js index 90c8b39..9416a58 100644 --- a/src/google_map.js +++ b/src/google_map.js @@ -3,9 +3,6 @@ import React, { Component } from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; -// libs -import shallowEqual from 'fbjs/lib/shallowEqual'; - // helpers import GoogleMapMap from './google_map_map'; import MarkerDispatcher from './marker_dispatcher'; @@ -22,8 +19,10 @@ import raf from './utils/raf'; import pick from './utils/pick'; import omit from './utils/omit'; import log2 from './utils/math/log2'; +import isEmpty from './utils/isEmpty'; import isNumber from './utils/isNumber'; import detectBrowser from './utils/detect'; +import shallowEqual from './utils/shallowEqual'; import isPlainObject from './utils/isPlainObject'; import isArraysEqualEps from './utils/isArraysEqualEps'; import detectElementResize from './utils/detectElementResize'; @@ -209,18 +208,13 @@ export default class GoogleMap extends Component { ); } - if ( - this.props.center === undefined && - this.props.defaultCenter === undefined - ) { + if (isEmpty(this.props.center) && isEmpty(this.props.defaultCenter)) { console.warn( 'GoogleMap: center or defaultCenter property must be defined' // eslint-disable-line no-console ); } - if ( - this.props.zoom === undefined && this.props.defaultZoom === undefined - ) { + if (isEmpty(this.props.zoom) && isEmpty(this.props.defaultZoom)) { console.warn( 'GoogleMap: zoom or defaultZoom property must be defined' // eslint-disable-line no-console ); @@ -288,17 +282,15 @@ export default class GoogleMap extends Component { componentWillReceiveProps(nextProps) { if (process.env.NODE_ENV !== 'production') { - if (this.props.defaultCenter !== nextProps.defaultCenter) { + if (!shallowEqual(this.props.defaultCenter, nextProps.defaultCenter)) { console.warn( - 'GoogleMap: defaultCenter prop changed. ' + // eslint-disable-line - "You can't change default props." + "GoogleMap: defaultCenter prop changed. You can't change default props." ); } - if (this.props.defaultZoom !== nextProps.defaultZoom) { + if (!shallowEqual(this.props.defaultZoom, nextProps.defaultZoom)) { console.warn( - 'GoogleMap: defaultZoom prop changed. ' + // eslint-disable-line - "You can't change default props." + "GoogleMap: defaultZoom prop changed. You can't change default props." ); } } @@ -337,26 +329,24 @@ export default class GoogleMap extends Component { } } - if (nextProps.zoom !== undefined) { + if (!isEmpty(nextProps.zoom)) { // if zoom chaged by user if (Math.abs(nextProps.zoom - this.props.zoom) > 0) { this.map_.setZoom(nextProps.zoom); } } - if ( - this.props.draggable !== undefined && nextProps.draggable === undefined - ) { + if (!isEmpty(this.props.draggable) && isEmpty(nextProps.draggable)) { // reset to default this.map_.setOptions({ draggable: this.defaultDraggableOption_ }); - } else if (this.props.draggable !== nextProps.draggable) { + } else if (!shallowEqual(this.props.draggable, nextProps.draggable)) { // also prevent this on window 'mousedown' event to prevent map move this.map_.setOptions({ draggable: nextProps.draggable }); } // use shallowEqual to try avoid calling map._setOptions if only the ref changes if ( - nextProps.options !== undefined && + !isEmpty(nextProps.options) && !shallowEqual(this.props.options, nextProps.options) ) { const mapPlainObjects = pick(this.maps_, isPlainObject); @@ -374,7 +364,7 @@ export default class GoogleMap extends Component { this.map_.setOptions(options); } - if (nextProps.layerTypes !== this.props.layerTypes) { + if (!shallowEqual(nextProps.layerTypes, this.props.layerTypes)) { Object.keys(this.layers_).forEach(layerKey => { this.layers_[layerKey].setMap(null); delete this.layers_[layerKey]; @@ -395,7 +385,7 @@ export default class GoogleMap extends Component { componentDidUpdate(prevProps) { this.markersDispatcher_.emit('kON_CHANGE'); - if (this.props.hoverDistance !== prevProps.hoverDistance) { + if (!shallowEqual(this.props.hoverDistance, prevProps.hoverDistance)) { this.markersDispatcher_.emit('kON_MOUSE_POSITION_CHANGE'); } } @@ -453,7 +443,7 @@ export default class GoogleMap extends Component { }; _computeMinZoom = minZoom => { - if (minZoom !== undefined && minZoom !== null) { + if (!isEmpty(minZoom)) { return minZoom; } return this._getMinZoom(); @@ -541,7 +531,7 @@ export default class GoogleMap extends Component { : this.props.options; const defaultOptions = defaultOptions_(mapPlainObjects); - const draggableOptions = this.props.draggable !== undefined && { + const draggableOptions = !isEmpty(this.props.draggable) && { draggable: this.props.draggable, }; @@ -555,7 +545,7 @@ export default class GoogleMap extends Component { ...propsOptions, }; - this.defaultDraggableOption_ = preMapOptions.draggable !== undefined + this.defaultDraggableOption_ = !isEmpty(preMapOptions.draggable) ? preMapOptions.draggable : this.defaultDraggableOption_; diff --git a/src/google_map_markers.js b/src/google_map_markers.js index 1386831..e708ca8 100644 --- a/src/google_map_markers.js +++ b/src/google_map_markers.js @@ -1,9 +1,9 @@ -/* eslint-disable react/forbid-prop-types */ - import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import shallowEqual from 'fbjs/lib/shallowEqual'; + +// utils import omit from './utils/omit'; +import shallowEqual from './utils/shallowEqual'; const mainStyle = { width: '100%', @@ -25,6 +25,7 @@ const style = { }; export default class GoogleMapMarkers extends Component { + /* eslint-disable react/forbid-prop-types */ static propTypes = { geoService: PropTypes.any, style: PropTypes.any, @@ -38,6 +39,7 @@ export default class GoogleMapMarkers extends Component { projectFromLeftTop: PropTypes.bool, prerender: PropTypes.bool, }; + /* eslint-enable react/forbid-prop-types */ static defaultProps = { projectFromLeftTop: false, diff --git a/src/utils/shallowEqual.js b/src/utils/shallowEqual.js new file mode 100644 index 0000000..f76994b --- /dev/null +++ b/src/utils/shallowEqual.js @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @providesModule shallowEqual + * @typechecks + * @flow + */ + +const hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * inlined Object.is polyfill to avoid requiring consumers ship their own + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is + */ +function is(x: mixed, y: mixed): boolean { + // SameValue algorithm + if (x === y) { + // Steps 1-5, 7-10 + // Steps 6.b-6.e: +0 != -0 + // Added the nonzero y check to make Flow happy, but it is redundant + return x !== 0 || y !== 0 || 1 / x === 1 / y; + } + // Step 6.a: NaN == NaN + // eslint-disable-next-line no-self-compare + return x !== x && y !== y; +} + +/** + * Performs equality by iterating through keys on an object and returning false + * when any key has values which are not strictly equal between the arguments. + * Returns true when the values of all keys are strictly equal. + */ +function shallowEqual(objA: mixed, objB: mixed): boolean { + if (is(objA, objB)) { + return true; + } + + if ( + typeof objA !== 'object' || + objA === null || + typeof objB !== 'object' || + objB === null + ) { + return false; + } + + const keysA = Object.keys(objA); + const keysB = Object.keys(objB); + + if (keysA.length !== keysB.length) { + return false; + } + + // Test for A's keys different from B. + for (let i = 0; i < keysA.length; i++) { + if ( + !hasOwnProperty.call(objB, keysA[i]) || + !is(objA[keysA[i]], objB[keysA[i]]) + ) { + return false; + } + } + + return true; +} + +module.exports = shallowEqual; +/* src: https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/shallowEqual.js */ diff --git a/yarn.lock b/yarn.lock index 1d4e9d5..96d4626 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2277,7 +2277,7 @@ fastparse@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" -fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.3, fbjs@^0.8.9: +fbjs@^0.8.1, fbjs@^0.8.16, fbjs@^0.8.9: version "0.8.16" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.16.tgz#5e67432f550dc41b572bf55847b8aca64e5337db" dependencies: