diff --git a/modules/Media.js b/modules/Media.js index 1ca8ded..b6995e2 100644 --- a/modules/Media.js +++ b/modules/Media.js @@ -3,6 +3,8 @@ import PropTypes from "prop-types"; import invariant from "invariant"; import json2mq from "json2mq"; +import MediaQueryList from "./MediaQueryList"; + /** * Conditionally renders based on whether or not a media query matches. */ @@ -52,13 +54,16 @@ class Media extends React.Component { let { query } = this.props; if (typeof query !== "string") query = json2mq(query); - this.mediaQueryList = targetWindow.matchMedia(query); - this.mediaQueryList.addListener(this.updateMatches); + this.mediaQueryList = new MediaQueryList( + targetWindow, + query, + this.updateMatches + ); this.updateMatches(); } componentWillUnmount() { - this.mediaQueryList.removeListener(this.updateMatches); + this.mediaQueryList.cancel(); } render() { diff --git a/modules/MediaQueryList.js b/modules/MediaQueryList.js new file mode 100644 index 0000000..f4eb053 --- /dev/null +++ b/modules/MediaQueryList.js @@ -0,0 +1,17 @@ +export default class MediaQueryList { + constructor(targetWindow, query, listener) { + const nativeMediaQueryList = targetWindow.matchMedia(query); + this.active = true; + // Safari doesn't clear up listener with removeListener + // when the listener is already waiting in the event queue. + // Having an active flag to make sure the listener is not called + // after we removeListener. + this.cancellableListener = (...args) => this.active && listener(...args); + nativeMediaQueryList.addListener(this.cancellableListener); + } + + cancel() { + this.active = false; + this.nativeMediaQueryList.removeListener(this.cancellableListener); + } +} diff --git a/yarn.lock b/yarn.lock index adad5a6..36c93a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,19 @@ # yarn lockfile v1 +"@types/prop-types@*": + version "15.5.5" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.5.5.tgz#17038dd322c2325f5da650a94d5f9974943625e3" + dependencies: + "@types/react" "*" + +"@types/react@*": + version "16.4.14" + resolved "https://registry.yarnpkg.com/@types/react/-/react-16.4.14.tgz#47c604c8e46ed674bbdf4aabf82b34b9041c6a04" + dependencies: + "@types/prop-types" "*" + csstype "^2.2.0" + abab@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" @@ -1114,6 +1127,10 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": dependencies: cssom "0.3.x" +csstype@^2.2.0: + version "2.5.7" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.5.7.tgz#bf9235d5872141eccfb2d16d82993c6b149179ff" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"