Reputation: 2426
I am developing a web app with React and need to detect when the screen size has entered the mobile break-point in order to change the state.
Specifically I need my sidenav to be collapsed when the user enters mobile mode and that is controlled with a boolean stored in the state within the component.
Upvotes: 60
Views: 180001
Reputation: 146
import { useState, useEffect } from 'react';
export default function useScreenWidth() {
const [windowWidth, setWindowWidth] = useState(null);
const isWindow = typeof window !== 'undefined';
const getWidth = () => isWindow ? window.innerWidth : windowWidth;
const resize = () => setWindowWidth(getWidth());
useEffect(() => {
if (isWindow) {
setWindowWidth(getWidth());
window.addEventListener('resize', resize);
return () => window.removeEventListener('resize', resize);
}
//eslint-disable-next-line
}, [isWindow]);
return windowWidth;
}
In a component, it returns the width size of the viewport, which can then be compared with a given numeric value
const widthSize = useScreenWidth()
const mobileWidth = 400
if(widthSize > mobileWidth){
//logic for desktop
}
if(widthSize <= mobileWidth){
//logic for mobile
}
Upvotes: 5
Reputation: 139
In Functional Component, we can detect screen size by useTheme and useMediaQuery.
const theme = useTheme();
const xs = useMediaQuery(theme.breakpoints.only('xs'));
const sm = useMediaQuery(theme.breakpoints.only('sm'));
const md = useMediaQuery(theme.breakpoints.only('md'));
const lg = useMediaQuery(theme.breakpoints.only('lg'));
const xl = useMediaQuery(theme.breakpoints.only('xl'));
Upvotes: 0
Reputation: 103
The react-screentype-hook library allows you to do this out of the box. https://www.npmjs.com/package/react-screentype-hook
You could use the default breakpoints it provides as follows
const screenType = useScreenType();
screenType has the following shape
{
isLargeDesktop: Boolean,
isDesktop: Boolean,
isMobile: Boolean,
isTablet: Boolean
}
Or you could even configure your custom breakpoints like this
const screenType = useScreenType({
mobile: 400,
tablet: 800,
desktop: 1000,
largeDesktop: 1600
});
Upvotes: 3
Reputation: 354
const [isMobile, setIsMobile] = useState(false)
//choose the screen size
const handleResize = () => {
if (window.innerWidth < 720) {
setIsMobile(true)
} else {
setIsMobile(false)
}
}
// create an event listener
useEffect(() => {
window.addEventListener("resize", handleResize)
})
// finally you can render components conditionally if isMobile is True or False
Upvotes: 35
Reputation: 2720
Using hooks in React(16.8.0+) refering to: https://stackoverflow.com/a/36862446/1075499
import { useState, useEffect } from 'react';
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}
Upvotes: 18
Reputation: 1410
What I did is adding an event listener after component mount:
componentDidMount() {
window.addEventListener("resize", this.resize.bind(this));
this.resize();
}
resize() {
this.setState({hideNav: window.innerWidth <= 760});
}
componentWillUnmount() {
window.removeEventListener("resize", this.resize.bind(this));
}
EDIT: To save state updates, I changed the "resize" a bit, just to be updated only when there is a change in the window width.
resize() {
let currentHideNav = (window.innerWidth <= 760);
if (currentHideNav !== this.state.hideNav) {
this.setState({hideNav: currentHideNav});
}
}
UPDATE: Time to use hooks!
If you're component is functional, and you use hooks - then you can use the useMediaQuery
hook, from react-responsive
package.
import { useMediaQuery } from 'react-responsive';
...
const isMobile = useMediaQuery({ query: `(max-width: 760px)` });
After using this hook, "isMobile" will be update upon screen resize, and will re-render the component. Much nicer!
Upvotes: 113
Reputation: 4704
There are multiple ways to archive this first way is with CSS using this class
@media screen and (max-width: 576px) {}
any class inside this tag will only be visible when the screen is equal or less than 576px
the second way is to use the event listener
something like this
constructor(props)
{
super(props);
this.state = {
isToggle: null
}
this.resizeScreen = this.resizeScreen.bind(this);
}
componentDidMount() {
window.addEventListener("resize", this.resizeScreen());
}
resizeScreen() {
if(window.innerWidth === 576)
{
this.setState({isToggle:'I was resized'});
}
}
even with the event listener I still prefer the CSS way since we can use multiple screen sizes without further js coding.
I hope this helps!
Upvotes: 2
Reputation: 1549
This is the same as @Ben Cohen answer but after attaching your function to eventListner, also remove it on componentWillUnmount
constructor() {
super();
this.state = { screenWidth: null };
this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
}
componentDidMount() {
window.addEventListener("resize", this.updateWindowDimensions());
}
componentWillUnmount() {
window.removeEventListener("resize", this.updateWindowDimensions)
}
updateWindowDimensions() {
this.setState({ screenWidth: window.innerWidth });
}
Upvotes: 9
Reputation: 126
hey I just published a npm package for this issue. Check it out https://www.npmjs.com/package/react-getscreen
import React, { Component } from 'react';
import {withGetScreen} from 'react-getscreen'
class Test extends Component {
render() {
if (this.props.isMobile()) return <div>Mobile</div>;
if (this.props.isTablet()) return <div>Tablet</div>;
return <div>Desktop</div>;
}
}
export default withGetScreen(Test);
//or you may set your own breakpoints by providing an options object
const options = {mobileLimit: 500, tabletLimit: 800}
export default withGetScreen(Test, options);
Upvotes: 3