Sometimes we are given a screen or PSD which have different layouts for mobile and desktop or for that matter even tablets and we need to render the layout with respect to device resolution. We know that we have been doing this from ages using media queries in CSS, but when it comes to ReactJS just hiding the element won’t do better. Because the components are still getting initialized, the lifecycle methods are getting invoked, rendering/re-rendering is not stopping and what not. Below is the example to demonstrate this, although its quite obvious but just to make a point.
Example with media queries
Visit the code link and check the output, we can see the text isn't displayed in non mobile resolution which is what we wanted but if we look at console we can see ‘Component mounted’ being printed. This is quite natural as the components will render, because media query just hides the element. Also see the below screenshot where we can see the element h1 can be seen on the DOM and media query applied to it.
The above example is just to demonstrate the point, it wouldn’t harm us much even if the component gets called on Desktop, but in real world, the scenarios are quite complex and will cost us much. Let’s take an example of filters, where user can filter data as per the preference. Now these filters have different appearances on mobile and desktop and demand us to create a different component for each. So if we go with media queries in this situation, we can though achieve the task but the listeners, state management, rendering/re-rendering will continue to work for both components irrespective of device resolution. This can have a bad impact on the performance considering mobile is a constrained device.
Available libraries to resolve this issue
Yes there is definitely a solution to this problem and we do have a quite mature library for this. I highly recommend to checkout library react-device-detect, this library has a good user base too.
Issue with library
Although this library works just a breeze on all device resolutions in production environment but when it comes to development environment it becomes difficult to debug. The reason is, in production environment we will definitely check the feature on real devices like mobiles or tablets but while debugging we will use browsers inbuilt tool like chrome’s ‘Toggle device toolbar’. So the issue is when we change the responsive layout or when we select any other device from the toolbar the changes to the respective components doesn’t happen instant. The reason is the library doesn’t listen for any changes for device resolution being changed in browser, the library is dependent on browsers navigator API and will provide the correct flag like isMobile or isBrowser, etc when we invoke it the first time but the moment we change the device resolution it won’t work, thats quite natural because it isn’t listening for any changes and also it isn’t the purpose of this library. We know we don’t care about this on production environment but we do care about our efficiency while debugging.
Solution to the problem
Ok enough talking, let get straight to the solution. We can just listen to inbuilt resize event provided by browser and can then detect the device resolution using window.innerWidth.
handleWindowResize() {
const resolution = window.innerWidth;
const isMobile = resolution >= 320 && resolution <= 480;
const isTablet = resolution >= 768 && resolution <= 1024;
const isDesktop = !isMobile && !isTablet;
// update state
}
componentDidMount() {
// invoke this for initial render
this.handleWindowResize();
// listen for resize event and handle resolution stuff in callback handler
window.addEventListener("resize", this.handleWindowResize.bind(this));
}
I have created a small library for this, please do checkout on Github react-device-identifier for documentation and usage. The library isn’t very exhaustive, I kept it simple which works on most scenarios. Check the code sample below using this lightweight library.
Closing note
What you think about this problem statement? Do you have better solution for this or do have any other alternative solution for this. Let me know in the comment box, also do provide opinions and suggestions for the library I have created.