loading...

Introducing Responsive React Components πŸ”₯

flexdinesh profile image Dinesh Pandiyan Updated on ・3 min read

Responsive React Components

TL;DR - You can render viewport specific components in React with a one-liner

React is awesome and the whole world agrees to it unanimously. Development is a whole lot faster and easier when we look at everything as components. Since everything is JavaScript driven, React renders only the code that is necessary based on application's state. It doesn't matter if you have over a thousand components and tens of thousands of lines of code. If you lazy load your components, you load only what's necessary for the user and I think that is the biggest win with using React.

That being said, have you ever wondered what happens when you write media queries in your React codebase?

You render elements that's not supposed to be in a particular viewport and hide it using css.

In this example

import React from 'react';
import './Example.style.scss';

const Example = () => {
  return (
    <div className="example">
      <div className="mobile-only">I'm a fancy mobile div</div>
      <div className="desktop-only">I'm a heavy desktop div</div>
    </div>
  );
};

Example.style.scss file

.example {
  .mobile-only {
    @media (min-width: 768px){
      display: none;
    }
  }
  .desktop-only {
    @media (max-width: 767px){
      display: none;
    }
  }
}

When Example component renders, both .mobile-only and .desktop-only elements will be rendered in the DOM but .mobile-only div will be hidden in bigger viewports and .desktop-only div will be hidden in smaller viewports with css display: none.

This is okay if this is small. But in one of the projects I worked, we had a heavy desktop menu and a heavy mobile menu both rendered in all the viewports. Just the Menu alone should be around 20Kb in size each and we easily had an unwanted 20Kb being loaded into the browser for each user. If you have more viewport specific elements, this size is going to keep increasing.

Introducing React Socks

React Socks is a minimal React library to render components based on viewport.

Say goodbye to media-queries. Here's how you can render viewport specific components with an uber-cool syntax.

const Example = () => {
  return(
    <Breakpoint small down>
      <MyAwesomeMobileMenu>
        This component will render only in mobile devices
      </MyAwesomeMobileMenu>
    </Breakpoint>
  );
};
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 large up>
        <div>I will render in laptops, desktops and everything bigger</div>
      </Breakpoint>
    </div>
  );
};

And that's not just it. You can specify your own breakpoints (as many as you want wow!) and use them according to your project needs. Also, you will have to setDefaultBreakpoints only once in your project 😎

import { setDefaultBreakpoints } from 'react-socks';

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

These are my favourite breakpoints

setDefaultBreakpoints([
  { cats: 0 },
  { dinosaurs: 900 }
]);

<Breakpoint cats only>
    Only cats can render me 🐈
</Breakpoint>

Reasons why you should use React Socks

  • Render viewport specific components without hassle
  • You can define your own breakpoints (Eg. xs, ipad, bigmonitors) and use them
  • You can improve your app performance if you lazy load your viewport specific components
  • Simpler and sweeter syntax for ease of use

The library has been published to npm and is in alpha version. I'd love to get your feedback and improve it before releasing the first stable version.

Edit: The first stable version has been released on Dec 9, 2018 with performance improvements and SSR support. πŸŽ‰

If you're wondering why the name React Socks πŸ€·β€β™‚οΈ

React Socks wraps your components comfortably to prevent unnecessary render in various viewports, just like how you wrap your feet with socks to prevent cold feet πŸŽ‰

Let's put some fancy React Socks on and wrap all the components πŸ”₯

You are amazing! Have a great day! ⚑️

Posted on Feb 10 '18 by:

flexdinesh profile

Dinesh Pandiyan

@flexdinesh

Engineer | Speaker | Blogger | OSS | I build things β˜•

Discussion

markdown guide
 

In my opinion this goes against mobile first principles. On occasion having device specific content is necessary (like you mentioned with the menu), however, if the component is handled appropriately, media queries is all you need.

And with your approach you're still having to write device specific styles.

I also see your point in wanting to min/max. Even if you handled the menu with specific device media-queries, you would still be loading the media queries not needed for desktop as an example.

I still stand with if media-queries can handle the change, then you should stick with media-queries without having to write device specific components.

20kb is quite a bit to just handle one device specific view, the menu must be really massive.

 

In my opinion this goes against mobile first principles

Mobile first approach is the dream and I agree that this goes against mobile first principles but in my experience there's always something that cannot be truly responsive and needs to be handled with media queries.

And with your approach you're still having to write device specific styles

Yes, but these styles will be composed for specific components without having to be wrapped in css media queries.

if you handled the menu with specific device media-queries, you would still be loading the media queries not needed for desktop as an example

Not necessarily. If you use css modules or any css-in-js approach, your styles will be a part of your component and not separate stylesheet. But this is true if you extract your css into one big stylesheet. Instead you could separate your stylesheet for specific components and lazy load them.

I still stand with if media-queries can handle the change, then you should stick with media-queries without having to write device specific components.

I hear you. You don't need this if the application or requirement is small. But if your application is huge and if you often find yourself writing device specific media queries, this will make you happier.

20kb is quite a bit to just handle one device specific view, the menu must be really massive.

It was one big bundle of bloated foundation elements wrapped in React components with a very high level of customization.

 

I'd say it depends on what you are building specifically. If it's for visual presentation, then yes you should use CSS media queries. But this would be helpful for when you want to serve different components for different device types (say a bare-bones video embed for phones, but a full featured media player for laptops up).

 

It's a brilliant idea. Keep doing great stuff, Dinesh!

 

In the sake of performance I would choose an extra element + media query over a resize listener updating state on every pixel. I think a nice feature would be to enable a throttled resize to minimize re renders and help with performance

 

updating state on every pixel

I agree that state change on every pixel of resize is a major overhead, but in reality we resize the browser window often only during development to check different viewports. End users don't do that that much.

I think a nice feature would be to enable a throttled resize to minimize re renders and help with performance

That definitely has to be done. There's a open issue for this throttling the window resize event. Planning to get this done soon.

 

This is interesting and I love the name! React Socks.. lol

 

Haha. Thanks Eric. I had sleepless nights trying to come up with a good night. Finally gave up to 'looking at one of my socks lying on the floor and naming the package'.

Whoever said "naming things is the most difficult part of software engineering", said it right.

 
 

This I’m used window resize events which can have performance costs. I’ve just written a package which uses matchMedia for optimal performance npmjs.com/package/react-device-bre...

 

Simon - What would help everyone is if you could explain the "performance costs" you quoted here.

BTW, as much as I wish my best for the commendable work you've put in your lib, I don't appreciate you promoting it here. If you wanted to improve this lib, you could've created an issue and we could have worked on it together. But if you want to promote your lib by dismissing what I've built, I don't appreciate it.

 

Sorry, the package I wrote came out of a problem I was trying to solve at work. All the responsive packages out there test breakpoints based on window size, meaning they listen to the window resize event which can have performance costs, then if you denounce you can get weird jumping of content.

My approach uses match media which is native to the browser and listens to the change event for each media query which is far more performant.

Was just letting people know there is an alternative approach, wasn’t down playing anything you had written.

I had already written my package and came across this post later.

I think it would have been a hard one to contribute to just because the approaches are completely different.

Sorry didn’t mean to tread on anyone’s toes. My original post was brief just because I was out and about so didn’t have time to write a detailed explanation

 
 

One other user in a reddit forum suggested to look into matchMedia and I think it's really interesting.

With this, we could let users to pass in custom css queries on the fly.

 
 
Sloan, the sloth mascot Comment marked as low quality/non-constructive by the community View code of conduct

Look at this bloated shit. JSX? Before, making up a completely new syntax would be seen as a bad idea, but now a mega corporation like Facebook is doing it, it's suddenly great. This is why I would recommend Vue. It embraces normal JS syntax, and it's really a joy to work with.

 

OK. Cut the talk. Show me the code.

 

Before anyone says "oh but you don't have to use JSX": If it's optional, shouldn't React samples be shown in normal syntax, which is easier for beginners to comprehend?

 

I am personally of the opinion that JSX is way easier to comprehend than nested React.createElement calls, but I do think it's important for beginners to eventually learn what's happening under the hood of the JSX magic.

Check out redom/hyperscript then tell me nested createElement calls look ugly.