React-responsive: Conditional rendering of components
This article is about rendering React components based on the current device (or based on the viewport). Let’s say we need to display component <SideNav/> when on the desktop but component <TopNav/> on mobile.
This can be achieved through conditional rendering of React components. We all know what conditional rendering is in React.js, but I am here to share my experience in dealing with detecting the viewport BEFORE conditional rendering.
If you are just here for the solution — check out the NPM packages —
Our Goal
In the end, we should be able to render React components conditionally, as shown below. Note that we will use placeholders for the TopNav and SideNav components:
<Responsive
displayIn={[
"Laptop"
]}>
<SideNav />
</Responsive><Responsive
displayIn={[
"Tablet",
"Mobile"
]}
>
<TopNav />
</Responsive>
Here, I am sharing the working example of this project in codesandbox, for better understanding —
https://codesandbox.io/s/friendly-breeze-72tel
Our small project
Step 1: Get all the breakpoints in an object. Please note that these values were derived from chrome’s developer tool:
export const DeviceWidthObject = { MobileSmall : { max: 320, min: 0 },
MobileMedium : { max: 375, min: 321 },
MobileLarge : { max: 767, min: 376 }, Tablet : { max: 991, min: 768 }, LaptopSmall : { max: 1024, min: 992 },
LaptopLarge : { max: 1440, min: 1025 }, LargerThanLaptop : { max: 2560, min: 1441 },
LargeScreenMax : { max: 999999, min: 2561 }};export const IdDeviceBreakpointsByWidth = {
laptop_max : 1440,
laptop_min : 992,
tablet_min : 768,
tablet_max : 991,
mobile_max : 767,
default_min : 768 // Unrecognized device
}export const IdMobileHeight = {
mobileLandscape_min : 320,
mobileLandscape_max : 425
}
Step 2: Get the current window dimension function. This function will help in getting the current viewport size through which we can derive the device type:
export const getWindowDimension = () => {const width = window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;const height = window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight;return {width, height}};
Step 3: This is going to be a massive function which derives the device type. I know it’s a big function, but it’s very simple, mostly chunks of if-else blocks:
> Please note: Up until now, you can pull all the above code in a single file, say
utilResponsive.js
Also, there is another thing to note in the above code block — the handleExceptions()
function. This is a special function which is checked before the main function is run. At the moment it only detects iPad Pro
as its screen size is as big as a laptop screen.
Step 4: Lastly, we need to create a React component which we can import and implement the conditional rendering. This file can be named - Responsive.js
:
import React from 'react'
import {
getWindowDimension,
IdDeviceBreakpointsByWidth,
IdMobileHeight
} from './utilResponsive'const { width, height } = getWindowDimension()
const initialState = { width, height }export class Responsive extends React.PureComponent {
state = initialState
componentDidMount () {
window.addEventListener('resize', this.handleResize, false)
}
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize, false)
}
render = () => {
const { children, displayIn } = this.props
const { width, height } = this.state
const shouldRenderChildren = this.shouldRender(displayIn, width, height) return (
<React.Fragment>
{shouldRenderChildren ? children : null}
</React.Fragment>
)
}
handleResize = () => {
const { width, height } = getWindowDimension()
this.setState({ width, height })
}
shouldRender = (display, width, height) => {
if (
display.indexOf('Laptop') !== -1 &&
width >= IdDeviceBreakpointsByWidth.laptop_min
) {
return true
}
if (
display.indexOf('Tablet') !== -1 &&
(width <= IdDeviceBreakpointsByWidth.tablet_max &&
width >= IdDeviceBreakpointsByWidth.tablet_min)
) {
return true
}
// For mobile regardless of orientation
if (
display.indexOf('Mobile') !== -1 &&
width <= IdDeviceBreakpointsByWidth.mobile_max
) {
return true
}
if (
display.indexOf('MobilePortrait') !== -1 &&
(width <= IdDeviceBreakpointsByWidth.mobile_max &&
height >= IdMobileHeight.mobileLandscape_max)
) {
return true
} return !!(
display.indexOf('MobileLandScape') !== -1 &&
(width <= IdDeviceBreakpointsByWidth.mobile_max &&
height <= IdMobileHeight.mobileLandscape_min)
)
}
}
And that’s it! Our tiny little project is complete. Now to see it in action:
- Import the
Responsive
React component we just created above in your container component (where you want to have the conditional rendering). - Use it as follows:
<>
<Responsive displayIn={["Laptop"]}>
<SideNav />
</Responsive> <Responsive displayIn={["Mobile"]>
<TopNav />
</Responsive>
</>
Wrapping up
I hope all of the above makes sense. Please comment if you liked it or if it can be improved.
In case if you are looking for new challenges or a really exciting place to work, check out our open positions at Applike. We are hiring!
You will find the code here — https://github.com/applike/react-responsive
and a working example here — https://codesandbox.io/s/friendly-breeze-72tel
Thanks!