Responsive React

Tricks to keep your React site Mobile Friendly.

React provides to your Frontend a Simple, Stateless & Declarative Component architecture that keeps your app easy to understand and extend as it grows from 20 to 20,000+ lines of code. Like with any other new web technology, a couple basics you have picked along the way (Media Queries, Z-indexes, etc) will need to be revisited to adapt to the components mindset.

Cooking your Meat

http://cube-drone.com/comics/c/how-it-feels-to-learn-javascript-in-2016

One of the most important basics most websites will require is to make all components Responsive, that is: elements that responds to the needs of the users and the devices they are using.

Screen Size is not a constant

Yes, your device’s screen size, does change. http://ux.stackexchange.com/q/24255

Responsive Web allows us to adjust a website content into the best layout for the device displaying it.

A Responsive component is a component that can respond to screen size changes, adjusting its contents into the optimal layout for the given parameters.

https://developers.google.com/web/fundamentals/design-and-ui/responsive/

Take a look at the component above, notice how it responds to width changes by turning the days rows into columns once the screen size has increased beyond a certain threshold. This is a responsive component.

The First Principles behind Responsive components

Media Queries is a CSS3 module that “defines expressions allowing to tailor presentations to a specific range of output devices without changing the content itself.”
What this means is that using the special media directives on our HTML & CSS, we can load the styles that fit the content best for a given device.

In this example below we load the example.css when the max width exceeds 800px. And we hide the facet_sidebar class when the max width exceeds 600px.

<!-- CSS media query on a link element -->
<link rel="stylesheet" media="(max-width: 800px)" href="example.css" />

<!-- CSS media query within a stylesheet -->
<style>
@media (max-width: 600px) {
.facet_sidebar {
display: none;
}
}
</style>
https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries

We’re in React now

Now, in the React World, we don’t have pure css, we have CSS-in-JS. What this means is that either you adopt a hybrid approach using a global css specific to your project (which will stop you from reusing your components in other projects) or you start adding styles to each one of your Components in their JSX templates. The article below goes over the tradeoffs each approach has.


For the rest of this article, we will assume you took the red pill and decided to use inline styles like in the following example.

const divStyle = {   
color: 'blue',
backgroundImage: 'url(' + imgUrl + ')',
};
function HelloWorldComponent() {   
return <div style={divStyle}>Hello World!</div>;
}

(Note: While you can also use these libraries with the hybrid approach, it’s recommended that you only use the media queries in the css to prevent conflicts).

Responsive React Inline Styles

Now that we know what Media Queries are, and that we decided to use inline styles, where do we go from here? Well, we need to extend our components to use these queries somehow. Luckily for us, many people have already stumbled upon this issue and shared their solutions. Let’s go over some of them.

React Responsive (our recommendation):

This library provides a wrapper component with a familiar interface to media queries. The main advantage of this library is that your existing components won’t need to be modified in any way, and their state and properties will remain the same.

var MediaQuery = require('react-responsive');

var A = React.createClass({
render: function(){
return (
<div>
<div>Device Test!</div>
<MediaQuery query='(min-device-width: 1224px)'>
<div>You are a desktop or laptop</div>
<MediaQuery query='(min-device-width: 1824px)'>
<div>You also have a huge screen</div>
</MediaQuery>
<MediaQuery query='(max-width: 1224px)'>
<div>You are sized like a tablet or mobile phone though</div>
</MediaQuery>
</MediaQuery>
<MediaQuery query='(max-device-width: 1224px)'>
<div>You are a tablet or mobile phone</div>
</MediaQuery>
<MediaQuery query='(orientation: portrait)'>
<div>You are portrait</div>
</MediaQuery>
<MediaQuery query='(orientation: landscape)'>
<div>You are landscape</div>
</MediaQuery>
<MediaQuery query='(min-resolution: 2dppx)'>
<div>You are retina</div>
</MediaQuery>
</div>
);
}
});

React Responsive Mixin:

Mixins are no longer recommended by the React authors (See Mixins considered harmful) but if you don’t mind making an exception, this plugin might be the easiest solution to adapt on your codebase. This mixin adds the .media property to your components, allowing them to adapt themselves to the best layout.

var React = require('react');
var ResponsiveMixin = require('react-responsive-mixin');

var Component = React.createClass({
mixins: [ResponsiveMixin],
getInitialState: function () {
return { url: '/img/large.img' };
},
componentDidMount: function () {
this.media({maxWidth: 600}, function () {
this.setState({url: '/img/small.jpg'});
}.bind(this));
this.media({minWidth:601, maxWidth: 1024}, function () {
this.setState({url: '/img/medium.jpg'});
}.bind(this));
this.media({minWidth: 1025}, function () {
this.setState({url: '/img/large.jpg'});
}.bind(this));
},
render: function () {
return <img src={this.state.url} />;
}
});

React Responsive Decorator

This decorator uses almost the same code as the mixin above but allows using the library as a decorator instead.

import React from 'react';
import Responsive from 'react-responsive-decorator';
@Responsive
class MyComponent extends React.Component {
state = {
isMobile: false
}
componentDidMount() {
this.props.media({ minWidth: 768 }, () => {
this.setState({
isMobile: false
});
});
this.props.media({ maxWidth: 768 }, () => {
this.setState({
isMobile: true
});
});
}
render() {
const { isMobile } = this.state;
return (
<div>
{isMobile ?
<div>Mobile</div> :
<div>Not mobile</div>
}
</div>
);
}
}
export default MyComponent;
# Or, if you'd rather return a wrapped, Higher Order component, # export like so:
import React from 'react';
import Responsive from 'react-responsive-decorator';
class MyComponent extends React.Component {
(...)
}
export default Responsive(MyComponent);

Conclusion:

We analyzed a couple different ways of using Media Queries with React. When using a new framework like React it can feel like you are sacrificing existing functionality for convenience, but in reality when you understand the first principles, there is no reason why you can’t have your Cooked Meat and eat it.

twitter.com/elg0nz

Gonzalo Maldonado is a Tech Lead at The Must Win All Star Web & Mobile Consultancy.

Gonzalo is a customer-focused engineer who has helped teams scale from 5 to 500+. He has experience with everything from mobile apps, to DevOps, to a myriad of web frameworks. After hours Gonzalo likes hunting for vinyl, running, and grilling.