Giter Site home page Giter Site logo

farfetch / react-context-responsive Goto Github PK

View Code? Open in Web Editor NEW
26.0 8.0 11.0 456 KB

A package that provides a responsive context to your application, using React Context API.

License: MIT License

JavaScript 100.00%
react reactjs context-api responsive responsive-layout farfetch matchmedia css viewport mobile

react-context-responsive's Introduction

react-context-responsive

This project is no longer being actively maintained. FARFETCH has decided to archive this project, as widely adopted alternatives, like react-responsive, have become available.

We won't be accepting pull requests or responding to issues for this project anymore. Thank you for your understanding.

A package that provides a responsive context to your application, using React Context API.

It has the same API of redux-responsive and they are easily interchangeable.

Installation

$ yarn add @farfetch/react-context-responsive
$ npm i @farfetch/react-context-responsive

...and include it in your project

import { ResponsiveProvider, useResponsive } from '@farfetch/react-context-responsive';

Guidelines

Provider use

The app, ideally, should have only one <ResponsiveProvider>, usually at app.js, wrapping all the components.

You can have as much consumers (useResponsive, useIsMobile, Responsive, withResponsive and withIsMobile) as you need. When the Provider value changes, all the consumers will update.

Preferred consumers

The hooks (useResponsive and useIsMobile) are the preferred method of using the context, when possible.

Mobile device detection

When possible, use the withIsMobile and useIsMobile for mobile devices detection. In the future we might use it to automatically splitting of mobile-only code.

ResponsiveProvider Props

Prop Type Required Default Description
initialMediaType '_initial'
|  'xs'
|  'sm'
|  'md'
|  'lg'
|  'xl'
no 'xs' Initial media type before the calculation of the real measures
defaultOrientation 'landscape'
|  'portrait'
no null Initial orientation before the calculation of the real measures
children node yes - React component
breakpoints { xs: string, sm: string, md: string, lg: string, xl: string } no - Min breakpoints
breakpointsMax { xs: string, sm: string, md: string, lg: string, xl: string } no - Max breakpoints
mediaQueries { _initial: string, xs: string, sm: string, md: string, lg: string, xl: string } no - Represents the screen media queries (If this is passed, breakpoints and breakpointsMax props are obsolete)
mobileBreakpoint '_initial'
|  'xs'
|  'sm'
|  'md'
|  'lg'
|  'xl'
no - It's considered mobile until this breakpoint

Object returned by the useResponsive / withResponsive / Responsive:

Key Type Description
mediaType '_initial'
|  'xs'
|  'sm'
|  'md'
|  'lg'
|  'xl'
Current breakpoint name
orientation string Current browser orientation
isCalculated boolean False on first render. Once true, it means all breakpoints values are based on the window.
is { _initial: boolean, xs: boolean, sm: boolean, md: boolean, lg: boolean, xl: boolean } Object key breakpoint name and value boolean that shows if width is at a certain breakpoint
lessThan { _initial: boolean, xs: boolean, sm: boolean, md: boolean, lg: boolean, xl: boolean } Object key breakpoint name and value boolean that shows if width is less than a certain breakpoint
greaterThan { _initial: boolean, xs: boolean, sm: boolean, md: boolean, lg: boolean, xl: boolean } Object key breakpoint name and value boolean that shows if width is greater than a certain breakpoint

Object returned by the useIsMobile / withIsMobile:

Key Type Description
isMobile boolean If it's below the mobile breakpoint defined by mobileBreakpoint
isCalculated boolean False on first render. Once true, it means all breakpoints values are based on the window.

Usage and examples

To use the package, you must embrace your code with the ResponsiveProvider, following the guidelines.

The component has five different exported consumption APIs:

  • useResponsive: A hook which returns the responsive object
  • useIsMobile: A hook which returns an object with isMobile and isCalculated
  • Responsive: A render prop component
  • withResponsive: A HoC which passes the responsive data to the responsive prop
  • withIsMobile: A HoC which passes isMobile and isCalculated props only

How to setup

There are two possible options to configure your responsive provider with breakpoints or with mediaQueries

Using breakpoints and breakpointsMax

const breakpoints = {
  xs: "320px",
  sm: "576px",
  md: "960px",
  lg: "1280px",
  xl: "1800px"
};

const breakpointsMax = {
  xs: "319px",
  sm: "575px",
  md: "959px",
  lg: "1279px",
  xl: "1799px"
};

const App = () => {
    
    return (
        <ResponsiveProvider breakpoints={breakpoints} breakpointsMax={breakpointsMax}>
            <Content />
        </ResponsiveProvider>
    );
};

export default App;

Using mediaQueries

const mediaQueries = {
  _initial: "(min-width: 0px) and (max-width: 319px)",
  xs: "(min-width: 320px) and (max-width: 575px)",
  sm: "(min-width: 576px) and (max-width: 959px)",
  md: "(min-width: 960px) and (max-width: 1279px)",
  lg: "(min-width: 1280px) and (max-width: 1799px)",
  xl: "(min-width: 1800px)"
};

const App = () => {
    
    return (
        <ResponsiveProvider mediaQueries={mediaQueries}>
            <Content />
        </ResponsiveProvider>
    );
};

export default App;

How to consume the package

Rendering components with useResponsive hook. (Preferred method)

const Greetings = () => {
    const { lessThan } = useResponsive();
    
    if (lessThan.sm) {
        return (<p>Hello small screen!</p>);
    }
    
    return (<p>Hello medium/big screen!</p>);
};

export default Greetings;

Rendering components with useIsMobile hook. (Preferred method)

const Greetings = () => {
    const { isMobile } = useIsMobile();
    
    if (isMobile) {
        return (<p>Hello mobile!</p>);
    }
    
    return (<p>Hello desktop!</p>);
};

export default Greetings;

Rendering components with Responsive render prop component

class Greetings extends Component {
    render() {
        return (
            <ResponsiveProvider>
                <Content>
                    <Responsive>
                        { (responsive) => ( <Component1 currentBreakpoint={ responsive.mediaType } /> ) }
                    </Responsive>
                    <Responsive>
                        { (responsive) => ( <Component2 orientation={ responsive.orientation } /> ) }
                    </Responsive>
                </Content>
            </ResponsiveProvider>
        )
    }
}

export default Greetings;

Rendering components with withResponsive High-Order component

class Greetings extends Component {
    render() {
        return this.props.responsive.lessThan.sm ? <p>Hello small screen!</p> : <p>Hello big/small screen!</p>
    }
}

export default withResponsive(Greetings);

Rendering components with withIsMobile High-Order component

class Greetings extends Component {
    render() {
        return this.props.isMobile ? <p>Hello mobile!</p> : <p>Hello desktop!</p>
    }
}

export default withIsMobile(Greetings);

Additional notes

The _initial media type

The gap between window width 0 and the first breakpoint is called _initial media type.

It fixes a problem at redux-responsive in the calculation:

If the first breakpoint starts in a number bigger than 0 (let's call it X), it considers that everything between 0 and X as the first breakpoint when it's not true.

For example, our breakpoints start at 320 (XS), redux-responsive considers 270 as XS, a wrong calculation. We call it _initial.

React compatibility

React >= 16.8.0 is required to use this package as the ResponsiveProvider is hook-based.

The non-hook APIs just expose the useResponsive hook with different APIs, for compatibility with class components.

Contributing

Read the Contributing guidelines

Disclaimer

By sending us your contributions, you are agreeing that your contribution is made subject to the terms of our Contributor Ownership Statement

Maintainers

License

MIT

react-context-responsive's People

Contributors

billdwhite avatar dependabot[bot] avatar joanaparaiba avatar mahish avatar nersoh avatar semantic-release-bot avatar soaresmg avatar stephan-noel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-context-responsive's Issues

Crashes if `process` is undefined`

Issue Report

If process is undefined, react-context-responsive crashes with:

Uncaught ReferenceError: process is not defined

Screen Shot 2021-08-11 at 9 44 38 AM

Expected Behavior

  • The app does not crash if process is undefined
  • The app does not log responsive changes if process is undefined

Actual Behavior

  • The app crashes when process is undefined.

Steps to Reproduce the Issue

  1. Open this StackBlitz application in Chrome
  2. Run npm run build
  3. Run npm run start
  4. Open DevTools & observe the following error:
    Screen Shot 2021-08-11 at 10 12 18 AM

useIsMobile uses hardcoded value

Issue Report

useIsMobile is using lessThan.md as a hardcoded value for the mobile breakpoint.

Expected Behavior

It should be possible to pass the breakpoint that divides mobile and desktop.
A solution could be passing that breakpoint as a prop to the provider and consequently to the context.

Actual Behavior

useIsMobile always uses lessThan.md

First render uses the first breakpoint it finds

Issue Report

Right now the first time ResponsiveProvider runs it will use the first option on breakpoints (which normally is the smallest one).

Expected Behavior

It should render the correct breakpoint of first usage.

Actual Behavior

There is a jump from the initial breakpoint to the correct one after useEffect runs the first time.

Steps to Reproduce the Issue

  1. Check example
  2. While being on desktop res it will quickly change from mobile to desktop (there is a visual jump)

Breakpoints do not change

Issue Report

When changing the breakpoints nothing happens.

Expected Behavior

It should be possible to change breakpoints and reflect those changes immediately.

Actual Behavior

Nothing happens, it uses the first breakpoints sent.

Steps to Reproduce the Issue

  1. Check example
  2. Click the button and check that it still uses the initial breakpoints

Consolidate the specification of breakpoints

Feature Report

I propose consolidating the specification of breakpoints into a single prop named breakpoints

Motivation

The current specification of breakpoints can be done either by 1) breakpoints and breakpointsMax or 2) mediaQueries. I see the following problems with this approach:

  • The naming of breakpoints and breakpointsMax is asymmetric.
  • The usage of breakpoints and breakpointsMax is unintuitive. Perhaps I'm not understanding the README well but breakpoints sm at 576px and breakpointsMax sm at 575px is not really conveying much to me. Wouldn't it be simpler to make a (possibly configurable decision) to be mobile first or desktop first?
  • breakpoints and breakpointsMax are partial. This just doesn't right, I get the feeling that a prop should fully specify the value on its own, not specify a part of a value. This partiality also leads to problems with required and default props stated below.
  • Because there are two different props for doing the same thing, the API is prevented from being able to supply a sensible default value for breakpoints for users who want to worry about customization later. It's true that we could check if a combination of the props are undefined, though this is somewhat clunky. The same applies to a prop being required, you can't specify that one of the props are required.
  • Larger than necessary API and the possibility of invalid prop combinations

Proposal

A single prop that serves to specify the breakpoints. If multiple formats are desired, this can be detected by the library itself instead of using multiple different props.

Comments

I could be misunderstanding the API but I'd like to know more about the motivation of these props and the need that motivated the creation of these additional props.

I'm aware that this would be a breaking change but I'm bringing it up early so that it can be discussed and considered and possibly batched along with other breaking changes.

Version of the package is not changing in the package.json automatically

Issue Report

The version of the package is not changing in the package.json automatically. We are already on version 1.0.2 and in package.json it still stays 1.0.0

Expected Behavior

Each time a merge to master happens the package.json should be changed automatically.

Actual Behavior

It isn't changed automatically.

Steps to Reproduce the Issue

I would say validate package.json and changelog

Mediaqueries setup - When going from desktop to mobile it doesnt update well the current breakpoint

Issue Report

When using the mediaQueries prop when I change from a desktop layout to a mobile it doesn't change the breakpoint.

Expected Behavior

The breakpoints should change depending on the mediaQueries that I passed as a prop

Actual Behavior

The breakpoint is not changing correctly

Steps to Reproduce the Issue

Use this codesandbox
https://codesandbox.io/s/polished-sun-9lwgh?file=/src/index.js

Open it in desktop (shows desktop) and resize to mobile it will continue showing desktop

Open it in mobile (shows mobile ) and resize to desktop it changes correctly, resize to mobile again and it will show desktop still.

MediaQueries setup

const mediaQueries = {
  _initial: "(min-width: 0px)",
  xs: "(min-width: 320px)",
  sm: "(min-width: 576px)",
  md: "(min-width: 960px)",
  lg: "(min-width: 1280px)",
  xl: "(min-width: 1800px)"
};

Update readme.md

Issue Report

We need to add some changes on readme, there was some props that weren't added:

  • breakpoints and breakpointsMax
  • mediaQueries

Add examples folder

Issue Report

We need to have an examples folder for the following scenarios:

  • Simple - Using breakpoints and breakpointsMax
  • Dynamic Queries - Passing mediaQueries manually

Tests are failing

Issue Report

Tests are failing due to the modifications made during the migration to github.

Expected Behavior

  • We shouldn't have any tests failling
  • New tests should be added regarding the ResponsiveProvider

Actual Behavior

  • Most of the tests are failing
  • Tests for ResponsiveProvider are outdated

Steps to Reproduce the Issue

Run yarn test

Increase react peer dependency

Hi, I just wonder whether there is any reason to keep React 16.9 as a peer dependency instead of current major version 17? I have to npm update --force everytime I want to update my projects because of this. Something like this would not work to not break older projects?

"peerDependencies": {
  "react": "^16.9 || ^17"
},

Thank you.

New 'mobileBreakpoint' property is not listed in typescript definition file

Issue Report

The new 'mobileBreakpoint' property is not listed in typescript definition file and thus displays as an error when used in combination with typescript checking.

Expected Behavior

The 'mobileBreakpoint' property will not show as an error when typescript checking is applied.

Actual Behavior

The 'mobileBreakpoint' property shows as an error when typescript checking is applied.

Steps to Reproduce the Issue

Use the 'mobileBreakpoint' property in a tsx React project and try using the 'mobileBreakpoint' property. Typescript will complain that the property is not valid.

console.log on ResponsiveProvider should not be in a production build

Issue Report

Right now we have some console.log to help debug the component.

These logs are wrapped by the following:

if (!process || !process.env || process.env.NODE_ENV !== 'test') {
  ...
}

If NODE_ENV is production it will be included in the bundle.

Expected Behavior

We should exclude those logs when building with NODE_ENV = "production".

To do this, we should follow webpack's production specs where they say that when the mode is production it will automatically call DefinePlugin and pass the mode to NODE_ENV.

So we could end up with something like this:

if (process && process.env && process.env.NODE_ENV !== 'production') {
  ...
}

When tree shaking happens it will consider that block as "dead code" and not add it to the final bundle.

I also checked if rollup was doing something similar and in their official docs they also set an example for process.env.NODE_ENV = 'production' as the way to go, you can check it here and here.

Actual Behavior

Right now those logs end up on the final bundle as you can see here:

image

Steps to Reproduce the Issue

Build a web app with the component using webpack or rollup and experiment with NODE_ENV at either development or production

Refactor ResponsiveProvider

Issue Report

Some functionality can be moved outside of this component, decreasing the clutter and making it clearer what is using the surrounding closure. I can pick this up.

Use TypeScript

Issue Report

Would you be in favor of rewriting this library using TypeScript?

Invalid props in ResponsiveProvider

Issue Report

There are some problems related to proptypes.

Expected Behavior

  • breakpoints should not trigger a warning.
  • mediaQueries and breakpointsMax should have clear shapes.

Actual Behavior

  • breakpoints is giving an invalid prop warning.
  • mediaQueries and breakpointsMax have PropTypes.any.

Steps to Reproduce the Issue

You can test this with yarn test

No warning about undefined variables

Issue Report

No warning about undefined variables

This should fix it: https://eslint.org/docs/rules/no-undef
(A clear and concise description of the issue)

Expected Behavior

I want eslint to tell me what are the variables which are not defined

(Write out the expected behavior here.)

Actual Behavior

I don't see any problem and only shows as soon as I run the unit tests

(Write out what actually happened here.)

Steps to Reproduce the Issue

Put on the code test = 2 and try to run the unit tests

(Write out detailed steps to reproduce the issue here.)

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.