advanced-react-apis icon indicating copy to clipboard operation
advanced-react-apis copied to clipboard

MediaQueryList.addListener Deprecated

Open DaleSeo opened this issue 4 years ago • 7 comments

I came across the following warning when I opened src/excercise/06.js in my editor.

image

After a bit of googling, I found the following guideline on MDN.

This method exists primarily for backward compatibility; if possible, you should instead use addEventListener() to watch for the change event.

https://developer.mozilla.org/en-US/docs/Web/API/MediaQueryList

DaleSeo avatar Nov 10 '20 02:11 DaleSeo

I just realized that using addEventListener() instead of addListener() breaks the unit tests. The underly library mq-polyfill is 3 years old and doesn't support the current best practice.

https://www.npmjs.com/package/mq-polyfill

DaleSeo avatar Nov 10 '20 02:11 DaleSeo

Thanks @DaleSeo! If you have a suggestion for improving this, that would be welcome :)

kentcdodds avatar Nov 10 '20 04:11 kentcdodds

@kentcdodds I think I'm interested in looking for a solution but I'm a bit concerned that if we got it fixed, your video wouldn't show the latest code. Would it be okay with you?

DaleSeo avatar Nov 10 '20 12:11 DaleSeo

Yeah, because that code isn't the focus of the video do it's fine.

kentcdodds avatar Nov 10 '20 14:11 kentcdodds

Created issues to request adding support for addEventListener/removeEventListener.

  • https://github.com/bigslycat/mq-polyfill/issues/7
  • https://github.com/paulirish/matchMedia.js/issues/86

DaleSeo avatar Nov 11 '20 12:11 DaleSeo

Hi everyone,

I was just thinking, since useMedia isn't really the focus here, the focus of the video is useDebugValue, wouldn't it be easier to replace it with a hook like useWithinWindowWidth

import { useState, useEffect, useDebugValue } from "react"

const formatDebugValue = ({ minWidth, maxWidth, isWithin }) => {
    if (maxWidth === Infinity) {
        return `(min-width: ${minWidth}px) => ${isWithin}`
    }

    if (minWidth === 0) {
        return `(max-width: ${maxWidth}px) => ${isWithin}`
    }

    return `(max-width: ${maxWidth}px) and (min-width: ${minWidth}px) => ${isWithin}`
}

function useWithinWindowWidth(minWidth, maxWidth) {
    const [width, setWidth] = useState(undefined)
    const isWithin = width && width >= minWidth && width <= maxWidth
    useDebugValue({ minWidth, maxWidth, isWithin }, formatDebugValue)

    useEffect(() => {
        const handleResize = () => setWidth(window.innerWidth)
        window.addEventListener("resize", handleResize)

        // Call handler right away so state gets updated with initial window size
        handleResize()
        return () => window.removeEventListener("resize", handleResize)
    }, [])

    return isWithin
}

function Box() {
    const isBig = useWithinWindowWidth(1000, Infinity)
    const isMedium = useWithinWindowWidth(700, 999)
    const isSmall = useWithinWindowWidth(0, 699)
    const color = isBig ? "green" : isMedium ? "yellow" : isSmall ? "red" : null
    return <div style={{ width: 200, height: 200, backgroundColor: color }} />
}

function App() {
    return <Box />
}

export default App

What do you think? Thanks!

mithi avatar Feb 07 '21 14:02 mithi

Thanks for the idea @mithi! When I update this workshop I may find an alternative hook for this example, or maybe I'll write my own polyfill.

kentcdodds avatar Feb 07 '21 14:02 kentcdodds