GithubHelp home page GithubHelp logo

merri / react-use-queries Goto Github PK

View Code? Open in Web Editor NEW
8.0 1.0 0.0 74 KB

[Buggy on Firefox] React hook for media queries on window and any container element. NOTE: Container Queries seem to be coming to browsers in 2022!

License: MIT License

JavaScript 100.00%
react react-hooks container-queries container-query element-queries element-query matchmedia breakpoints

react-use-queries's Introduction

react-use-queries

Version NPM-Size

This React hook makes it easy for you to match with your media queries. Be it window or any container element!

Get it: npm install react-use-queries --save

tiny ✔️ efficient ✔️ fast ✔️ powerful ✔️ cross-browser ✔️
dependencies ❌ polyfills ❌ ResizeObserver ❌

What?

Given things you want to do with your media queries you can ask for a list of things that match!

const queries = {
    '(max-width: 299px)': { thing: 'A' },
    '(min-width: 300px) and (max-width: 599px)': { thing: 'B' },
    '(min-width: 600px)': { thing: 'C' }
}

function ResponsiveComponent() {
    const [things] = useQueries(queries, global)
    // server side: = []
    // client side: = [{ thing: 'A' }]
    //          or: = [{ thing: 'B' }]
    //          or: = [{ thing: 'C' }]
    return (
        <div>
            Things that match:
            <pre>{JSON.stringify(things, null, 4)}</pre>
        </div>
    )
}

Global?

The global there is actually window, but Babel handles global so that both server and client side code can work! You can use window if you're dealing with client-only codebase (and don't have anything to fix global for you).

What about elements?

In this case you can omit use of the second parameter, but you must then place a mediaQueryListener element inside a container element.

import React, { useMemo } from 'react'
import useQueries from 'react-use-queries'

// define this outside component to keep the same reference
// or if you need this to be dynamic: useMemo
const queries = {
    '(max-width: 299px)': 'small',
    '(min-width: 300px) and (max-width: 599px)': 'medium',
    '(min-width: 600px)': 'large'
}

const positionRelative = { position: relative }

function ResponsiveComponent() {
    const [[size = 'default'], mediaQueryListener] = useQueries(queries)

    // for demo purposes set a width that is smaller than the viewport width
    const style = useMemo(() => ({ width: '50%', ...positionRelative }), [positionRelative])

    return (
        <div style={style}>
            {mediaQueryListener}
            <h2>Size is <code>{size}</code></h2>
        </div>
    )
}

mediaQueryListener is a single <iframe src="about:blank" /> element.

Can I use this with Styled Components?

Yes, here is a demo!

Caveats

For the media queries (or container queries) to work on elements you must give a containing element a style that is not static (or initial). Most commonly this means applying position: relative;. This is required, because a trick originating from 2013 used for element resize detection is used here in a modern flavor, but instead of detecting resize we use matchMedia instead. The mediaQueryListener element is an <iframe /> with url set to about:blank. Then this iframe element is sized to full size of it's parent by absolute positioning, hence requirement for position other than static.

All current container query solutions have issues with circularity: react-use-queries does nothing to protect against these, so you should always make sure your styles don't cause unintended side-effects. For example, changing parent element's border can change it's size which can then result to infinite resize loop as each style changes the content size. Also, parent element's size shouldn't be determined by it's children's size.

Motivation

You know how annoying it is to control element sizes via media queries in CSS? Well, I hadn't found out about container queries until just recently (around November 2019) and ended up reading and researching a lot on the topic. Also, I think I got a pretty unique idea using matchMedia of the about:blank page instead of resize events. Another idea was to output array of matches, which I think is both clever and simple way to create a powerful hook for all sorts of media and container query needs.

Inspiration and thanks

I used the excellent react-resize-aware as an inspiration for the minimal bundle size. Thanks to the author of that hook! Previusly I did some work creating use-element-query, but it uses DOM mutations outside React and also has a bit sloppier API. I ended up putting more effort into polishing this hook and even choosing a much better name.

Alternatives

And finally, I recommend react-resize-aware if you need to know about element resizing and don't want to use ResizeObserver due to current state of browser support!

react-use-queries's People

Contributors

merri avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

react-use-queries's Issues

doesn't handle resize on FF

Hi,

It works fine on the initial load, but if I resize the width of the window, it doesn't re-calculate the variable.

Is this intended and a limitation on Firefox?

Is there a debug mode to see what is triggered and when?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.