GithubHelp home page GithubHelp logo

flexdinesh / react-socks Goto Github PK

View Code? Open in Web Editor NEW
426.0 13.0 29.0 1.58 MB

๐ŸŽ‰ React library to render components only on specific viewports ๐Ÿ”ฅ

License: MIT License

JavaScript 100.00%
breakpoints media-queries viewport react library

react-socks's Introduction

React Socks

Build Status npm version dependencies Status License: MIT

Wrap your components with React Socks to prevent unnecessary render in different viewports.

<Breakpoint small down>
  <MyAwesomeMobileMenu>
    This component will render only in mobile devices
  </MyAwesomeMobileMenu>
</Breakpoint>

Why? start with why

Conventionally we have been writing css media queries for different viewports to hide and show elements that are always present in the DOM. With React taking over the world, everything is about rendering components into the DOM. React Socks helps you conditionally render elements based on viewports.

  1. Render viewport specific components without hassle

  2. You can define your own breakpoints (Eg. xs, ipad, bigmonitors) and use them

  3. You can improve your app performance if you lazy load your viewport specific components

  4. Simpler and sweeter syntax for ease of use

Install

$ npm install --save react-socks

Usage

Just wrap your top level component with BreakpointProvider and use the Breakpoint component anywhere you need.

Note: BreakpointProvider was introduced only in v1.0.0. It's not available in previous alpha versions.

import  { Breakpoint, BreakpointProvider } from 'react-socks';

// entry file (usually App.js or index.js)
const App = () => (
  <BreakpointProvider>
    <Example />
  </BreakpointProvider>
);
// Example.js
const Example = () => {
  return (
    <div>
      <Breakpoint small down>
        <div>I will render only in mobile devices</div>
      </Breakpoint>

      <Breakpoint medium only>
        <div>I will render only in tablets (iPad, etc...)</div>
      </Breakpoint>

      <Breakpoint medium down>
        <div>I will render in tablets (iPad, etc...) and everything below (mobile devices)</div>
      </Breakpoint>

      <Breakpoint medium up>
        <div>I will render in tablets (iPad, etc...) and everything above (laptops, desktops)</div>
      </Breakpoint>

      <Breakpoint large up>
        <div>I will render in laptops, desktops and everything above</div>
      </Breakpoint>

      {/* Add breakpoints on the fly using custom queries */}

      <Breakpoint customQuery="(min-width: 500px)">
        <div style={{backgroundColor: 'red' }}>
          Custom breakpoint: (min-width : 500px)
        </div>
      </Breakpoint>
      
      <Breakpoint customQuery="(max-width: 1000px)">
        <div style={{backgroundColor: 'yellow' }}>
          Custom breakpoint: (max-width : 1000px)
        </div>
      </Breakpoint>
      
      <Breakpoint customQuery="(min-width: 500px) and (max-width: 700px)">
        <div style={{backgroundColor: 'lightblue' }}>
          Custom breakpoint: (min-width : 500px) && (max-width : 700px)
        </div>
      </Breakpoint>
    </div>
  );
};

API

Set Default Breakpoints

You can define your own breakpoints.

  • Pass an array of objects with the breakpoint name and width in px to setDefaultBreakpoints once in your App.js or your React entry file.

Note: You only need to set default breakpoints once in your app

import { setDefaultBreakpoints } from 'react-socks';

setDefaultBreakpoints([
  { xs: 0 },
  { s: 376 },
  { m: 426 },
  { l: 769 },
  { xl: 1025 }
]);

<Breakpoint m only>
    I will render only in m devices
</Breakpoint>
  • You can use any breakpoint name (Eg. cats, puppies, dinosaurs, etc) and width.
setDefaultBreakpoints([
  { cats: 0 },
  { dinosaurs: 900 }
]);

<Breakpoint cats only>
    Only cats can render me
</Breakpoint>
  • If you don't set a default breakpoint, the library will fallback to Bootstrap 4 default breakpoints as described below.
setDefaultBreakpoints([
  { xsmall: 0 }, // all mobile devices
  { small: 576 }, // mobile devices (not sure which one's this big)
  { medium: 768 }, // ipad, ipad pro, ipad mini, etc
  { large: 992 }, // smaller laptops
  { xlarge: 1200 } // laptops and desktops
]);

Set Default Width

You can define your own default width. This will help when you want to render a particular default width from the server. Usually in the server, there are no breakpoints and the lib defaults to 0 and renders mobile views. Use this API to change that.

  • Pass width in px to setDefaultWidth once in your App.js or your React entry file.

Note: You only need to set default width once in your app

import { setDefaultWidth } from 'react-socks';

setDefaultWidth(992); // render desktop components in the server

Breakpoint

Import the Breakpoint component anywhere in the your code and start using it with your breakpoint and modifier props.

// small is breakpoint
// down is modifier
<Breakpoint small down>
  <MyAwesomeMobileMenu>
    This component will render only in mobile devices
  </MyAwesomeMobileMenu>
</Breakpoint>

You have three modifiers

  • only - will render the component only in the specified breakpoint.

  • up - will render the component in the specified breakpoint and all the breakpoints above it (greater than the width).

  • down - will render the component in the specified breakpoint and all the breakpoints below it (less than the width).

Custom Breakpoints ๐Ÿ†•

Now, you can add a breakpoint of any width by using this prop: customQuery. Simply write your media query as a string and pass it to customQuery

  <Breakpoint customQuery="(min-width: 500px)">
    <div style={{backgroundColor: 'red' }}>
      Custom breakpoint: (min-width : 500px)
    </div>
  </Breakpoint>
  
  <Breakpoint customQuery="(max-width: 1000px)">
    <div style={{backgroundColor: 'yellow' }}>
      Custom breakpoint: (max-width : 1000px)
    </div>
  </Breakpoint>
  
  <Breakpoint customQuery="(min-width: 500px) and (max-width: 700px)">
    <div style={{backgroundColor: 'lightblue' }}>
      Custom breakpoint: (min-width : 500px) && (max-width : 700px)
    </div>
  </Breakpoint>

Note: customQuery will be ignored if you have mentioned any modifiers like up, down & only

Use customQuery only if you want to make use of arbitary breakpoints.

Use Current Width / Breakpoint Name

If you call useCurrentWidth in the render function, you can access the current width directly:

import { useCurrentWidth } from 'react-socks'

const CustomComponent = () => {
  const width = useCurrentWidth()
  if (width < 500) {
    return <h1>Hello!</h1>
  } else {
    return <h2>Hello!</h2>
  }
}

You can also use the current breakpoint name with useCurrentBreakpointName:

import { useCurrentBreakpointName } from 'react-socks'

const CustomComponent = () => {
  const breakpoint = useCurrentBreakpointName()
  if (breakpoint == 'small') {
    return <h1>Hello!</h1>
  } else {
    return <h2>Hello!</h2>
  }
}

Contributors

Thanks goes to these amazing people ๐ŸŽ‰


Dinesh Pandiyan


Capelo


Adarsh


Patryk


WRNGFRNK


Farhad Yasir


Entkenntnis


Douglas Moore


Abdul rehman


Nawaz Khan


hems.io

License

MIT ยฉ Dinesh Pandiyan

react-socks's People

Contributors

antoniocapelo avatar dator-frank avatar dbryantm avatar dependabot[bot] avatar entkenntnis avatar flexdinesh avatar hagmic avatar nawazeverlane avatar nutboltu avatar patrykrudzinski avatar rehman-00001 avatar sadarshannaiynar 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  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  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  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  avatar  avatar  avatar  avatar  avatar

react-socks's Issues

Cannot Resolve Symbol 'BreakpointProvider'

I'm currently testing out your library. I love the idea! However, when I try to import BreakpointProvider in my project, I receive an error, Cannot Resolve Symbol 'BreakpointProvider'. Outside of that, the breakpoints don't seem to be triggered. The root component only seems to load the component in the first Breakpoint (TabNav) regardless of whatever resolution I use.

import React from 'react';
import Breakpoint, { BreakpointProvider } from 'react-socks';

const TabNav = React.lazy(() => import('./TabNav'));
const ListNav = React.lazy(() => import('./ListNav'));

const Example = () => {
  return (
    <BreakpointProvider>
      <div className="example">
          <Breakpoint small down>
            <TabNav />
          </Breakpoint>
          <Breakpoint medium up>
            <ListNav />
          </Breakpoint>
      </div>
    </BreakpointProvider>
  );
};

export default Example;

I've also tried replacing both the TabNav and ListNav components with simple text in each breakpoint. The text in both breakpoints is displayed when the DOM is rendered regardless of the resolution.

React-Socks: 1.0.1
React: 16.8.1

Tests fail

Question: This code works localy but the test fails. Should this work with styled components too?
If so, I am not sure why this fails.
Example.jsx:

import * as React from 'react';
import Breakpoint  from 'react-socks';

const Example = function({ data, ...other }: Props) {
    return (
        <Breakpoint > 
            <p>test</p>
        </Breakpoint>
    );
};

Example.test.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { ThemeProvider } from 'styled-components';
import Example from './Example';
import { mount } from 'enzyme/build';

describe('Example', () => {
    let div;

    afterEach(() => {
        ReactDOM.unmountComponentAtNode(div);
    });

    beforeEach(() => {
        div = document.createElement('div');
    });

    it('renders without data without crashing', () => {
        ReactDOM.render(
            <ThemeProvider theme={theme}>
                <Example />
            </ThemeProvider>,
            div,
        );
        ReactDOM.unmountComponentAtNode(div);
    });
});

Error:

    Error: Uncaught [TypeError: Cannot read property 'currentBreakpointName' of undefined]

Package.json:

        "react": "16.6.3",
        "react-dom": "16.6.3",
        "react-socks": "^1.0.0",

Server-side rendering issue

I'd like to try out the library, seems interesting, but cannot because server-side rendering throws "ReferenceError: window is not defined".

Only importing the Breakpoint causes the error.

Any change to use window only at the point a Breakpoint is actually being used?

Cheers!

`window.removeEventListener` isn't removing the event listener

Hello again!

The event listener set here isn't being removed here. You'll have to pass the same function to both for it to be removed. I'd recommend creating a class method called onResize or something similar and adding this.onResize to both the addEventListener and removeEventListener calls.

I'll see if I get some free time to help out and make a few PR's to the project. Just wanted you to be aware of some of these things. Should help performance a bit!

Component Flashes on Screen

I've tried out your library for a react project of mine and it seems to work with the breakpoints, however, regardless of the width, the components will always flash on the screen then disappear. For example:

        <Breakpoint xlarge up>
          <SearchBar />
        </Breakpoint>

For the above code, I want the search bar to render only for screens larger than xlarge. When the screen size is small (mobile), the SearchBar flashes on the screen then disappears. Which tells me that, while the library is adhering to the screen sizes, it is still rendering the component and then unmounting it.

Is there a fix for this?

v2.0.0 - Typings issue for Breakpoint and useCurrentWidth/useCurrentBreakpointName

The new TypeScript typings break custom breakpoint names for Breakpoint (i.e. sm, md, lg, etc). I currently get the following error:

Type '{ children: Element; sm: true; down: true; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Breakpoint> & Readonly<Props> & Readonly<{ children?: ReactNode; }>'.
  Property 'sm' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Breakpoint> & Readonly<Props> & Readonly<{ children?: ReactNode; }>'.

Just a suggestion, but either have a breakpoint prop that accepts a string with the following typing (also probably more maintainable):

interface Props {
  children?: React.ReactNode;
  breakpoint?: string;
  up?: boolean;
  down?: boolean;
  only?: boolean;
  tagName?: string;
  className?: string;
}

Or change the Props typing to the following (which unfortunately lets more in but doesn't restrict the use of the library):

interface Props<T extends any> {
  children?: React.ReactNode;
  up?: boolean;
  down?: boolean;
  only?: boolean;
  tagName?: string;
  className?: string;
}

Also, you're missing typings for useCurrentWidth and useCurrentBreakpointName:

export function useCurrentWidth(): number;
export function userCurrentBreakpointName(): string;

Server side rendering wrong css styles

I've got Header that renders different elements depending on viewport. When mobile page is loaded, some css styles from desktop viewport are stay on mobile viewport elements, which is strange:

<Breakpoint medium up>
  <div1 />
  <div2 className='a' />
  <div3 />
</Breakpoint>
<Breakpoint small down>
  <div4 />
  <div5 />
  <div6 />
</Breakpoint>

on mobile viewports results in:

...
  <div4 />
  <div5 className='a' />
  <div6 />
...

Where <divN> some component.

Hard Refresh in Browser Produces Warning and Incorrect CSS

We are attempting to use react-socks with Next.js. However, when a hard refresh is executed in the browser we get the wrong CSS applied to the markup as there seems to be a className mismatch. This issue is similar to the issue produced by Next.js when used with 'styled-components' if babel is not configured correctly. However, we are using an external sass file for the styling and not styled-components. Below is the warning from browser console when wrong className (add CSS) is applied. In this case, the client is using a mobile user-agent but the response from the server is for a desktop request. Initial requests work as expected, this issue only happens on refresh.

index.js:1 Warning: Prop className did not match. Server: "Example-style__desktopUA___3ICHb" Client: "Example-style__mobileUA___2vKnj"

PDF of sample code.

react-socks_Next.js.pdf

TypeError: Super expression must either be null or a function

The react website I'm building at the moment is throwing this error in the console.

It works just fine on localhost, but as soon as I deploy it to Netlify, the page is blank and I get this error in console pointed at react-socks/dist/index.js

I have no idea what could be causing this and why it gets triggered only in production.

Class name for undefined breakpoint

Hello,

Is there any way to remove the default class name added for an undefined breakpoint?

<Breakpoint customQuery="(max-width: 639px)">

Will export to:
<div class="breakpoint__undefined-undefined ">

Thanks

Not working with Swiper

I'm trying to use React-socks with Swiper, but the pictures don't render when wrapped within the max-width.

{/* Swiper mobile only */}
        {/* <Breakpoint customQuery="(max-width: 639px)"> */}
        <div className="w-full overflow-hidden">
          <div className="relative w-full">
            <Swiper
              style={{
                '--swiper-navigation-color': '#000',
                '--swiper-pagination-color': '#000',
              }}
              navigation={{}}
              pagination={{ clickable: true }}
              // eslint-disable-next-line tailwindcss/no-custom-classname
              className="custom-swiper h-96 rounded-2xl"
              loop={true}
            >
              {images}
            </Swiper>
          </div>
        </div>
{/* </Breakpoint> */}

Any ideas why it might break?

Typescript error with `style` prop

Here's a basic example which shows the issue: https://codesandbox.io/s/nifty-river-olt52e?file=/src/App.tsx

When we add a styles prop to a Breakpoint we get a Typescript error:

No overload matches this call.
  Overload 1 of 2, '(props: Props | Readonly<Props>): Breakpoint', gave the following error.
    Type '{ children: string; style: { background: string; }; sm: true; down: true; }' is not assignable to type 'Readonly<Props>'.
      Property 'style' is incompatible with index signature.
        Type '{ background: string; }' is not assignable to type 'ReactNode'.
          Property 'background' does not exist on type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.
  Overload 2 of 2, '(props: Props, context: any): Breakpoint', gave the following error.
    Type '{ children: string; style: { background: string; }; sm: true; down: true; }' is not assignable to type 'Readonly<Props>'.
      Property 'style' is incompatible with index signature.
        Type '{ background: string; }' is not assignable to type 'ReactNode'.
          Property 'background' does not exist on type 'ReactElement<any, string | JSXElementConstructor<any>> | ReactFragment | ReactPortal'.ts(2769)

Essentially the problem is the [key: string]: React.ReactNode | string | boolean; on ReactSocks.Props

One way to fix it is to change it to this:

[key: string]: React.ReactNode | React.CSSProperties | string | boolean;

We could use `matchMedia` to pass in custom media queries

We could make use of matchMedia to pass in custom media queries

A syntax like this would be really convenient

<Breakpoint customQuery={'(min-width: 400px)'}>
  <div>I will render only in mobile devices</div>
</Breakpoint>
  • Should not interfere with modifiers likesmall, medium, etc.
  • Should only effect when there are no modifiers.

Handling height

I found using react-socks quite straightforward, however, the single biggest thing which is holding it back is that, as far as I can tell, it does not handle height as well.

Example:
Mobile breakpoint works like a charm but as soon as I put my phone in landscape, Tablet breakpoint gets triggered. I can get by with some CSS hacks.

In time I'd like to contribute and maybe implement height handling as well.

Cheers.

Consider throttling the window resize event

React already throttles calls to setState, which is the only thing in the resize function currently - however it might be more clear/worthwhile in the future to throttle this function:

  componentDidMount() {
    window.addEventListener('resize', () => {
      this.setState({
        width: BreakpointUtil.currentWidth,
        currentBreakpoint: BreakpointUtil.currentBreakpointName
      });
    });
}

Cool library! Definitely look forward to trying it out on a project!

{ setDefaultBreakpoints } is not working properly

I am using { setDefaultBreakpoints } and have following breakpoints:

setDefaultBreakpoints([{ sm: 599 }, { md: 610 }]);

And, using to render:

<Breakpoint md down>
  <h1>I am only mobile</h1>
</Breakpoint>
<Breakpoint md up>
  <h1>I am not in mobile</h1>
</Breakpoint>

The issue is <h1>I am only mobile</h1> is showing in all the view-ports

Am I missing anything?

Styling on Mobile in build is lost

For some reason when i deploy my site to Netlify or with a new fresh build (Using Gatsby), the sections where I have used the plugin on mobile have no styles. The content stays, yet the styling doesnt.

Heres what it should look like (From dev)
https://ibb.co/g7NM1SS

Here's what it looking like in build
https://ibb.co/kccX19S

What can be causing this?

This is my code:

<Column key={index} small={12} large={4} mpad>
  <Breakpoint medium down>
    <Card icon={icon} heading={heading} excerpt={excerpt} />
  </Breakpoint>

  <Breakpoint large up>
    <Parallax y={[para, -para]}>
      <Card icon={icon} heading={heading} excerpt={excerpt} />
    </Parallax>
  </Breakpoint>
</Column>

TypeScript typings?

I'd love to use react-socks, but I'm working on a TS project, and this library doesn't have typings. Any chance of adding them? dts-gen may be able to automatically create during build-time.

Update: managed to adopt react-socks by adding generating react-socks.d.ts using dts-gen -m react-socks, then adding the output to my typings folder (wrapped as a module declaration: declare module "react-socks"{output}), but it would be nice if this was included.

Update 2: this just didn't work in my app for some reason, probably related to general strangeness of my project. Resorted to window.outerWidth >=, which will do fine :)

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.