365

How do I get the viewport height in ReactJS? In normal JavaScript I use

window.innerHeight()

but using ReactJS, I'm not sure how to get this information. My understanding is that

ReactDOM.findDomNode()

only works for components created. However this is not the case for the document or body element, which could give me height of the window.

Ty Mick
  • 75
  • 1
  • 7
Jabran Saeed
  • 5,760
  • 3
  • 21
  • 37

28 Answers28

728

Using Hooks (React 16.8.0+)

Create a useWindowDimensions hook.

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;
}

And after that you'll be able to use it in your components like this

const Component = () => {
  const { height, width } = useWindowDimensions();

  return (
    <div>
      width: {width} ~ height: {height}
    </div>
  );
}

Working example

Original answer

It's the same in React, you can use window.innerHeight to get the current viewport's height.

As you can see here

QoP
  • 27,388
  • 16
  • 74
  • 74
  • 10
    window.innerHeight is not a function, it's a property – Jairo Sep 03 '18 at 08:38
  • 2
    looks like Kevin Danikowski edited the answer and somehow that change was approved. It's fixed now. – QoP Sep 03 '18 at 09:01
  • can someone explains to me what is the line `return () => window.removeEventListener('resize', handleResize);` for? – FeCH Aug 15 '19 at 20:20
  • 4
    @FeCH it removes the event listener when the component is unmounted. It's called the `cleanup` function, you can read about it [here](https://reactjs.org/docs/hooks-effect.html#example-using-hooks-1) – QoP Aug 16 '19 at 06:05
  • 6
    Any ideas to get the same approach with SSR (NextJS)? – roadev Sep 05 '19 at 19:48
  • @roadev yes, just check if `window`'s available before anything `window`-related. I'll answer below. – giovannipds Dec 04 '19 at 21:27
  • 1
    @roadev at NextJS, you can also check if the `req` prop's available on `getInitialProps`. If it is, it's running on server, then you'll not have window variables. – giovannipds Dec 04 '19 at 21:28
  • 1
    @roadev here it goes https://stackoverflow.com/a/59185109/842768 – giovannipds Dec 04 '19 at 21:48
  • Do you / should you have to debounce the Event listener? – accelerate Jan 14 '20 at 07:03
  • @speckledcarp -- any specific reason you're encapsulating handleResize() inside useEffect? – unfollow Mar 14 '20 at 15:51
  • also... bouncing off of @FeCH's comment -- isn't this only going to invoke once and therefore not continuously update based on a resize event? – unfollow Mar 14 '20 at 15:58
  • 1
    @accelerate debounce? I'm not sure if I'm getting what you mean but you need to add the event listener and return a remove event listener function in order to it works well with `useEffect`. @QoP explained about it above. – giovannipds Mar 24 '20 at 03:20
  • @unfollow no, it'll not. It'll update add to the resize listener when needed and remove it when needed. – giovannipds Mar 24 '20 at 03:21
  • this is only valid for function components but not class components – 89n3ur0n Apr 08 '20 at 16:26
  • 33
    Such a well written answer. Wish more people wrote stackoverflow answers like this rather than publishing npm modules. – Ross Sep 04 '20 at 14:54
  • 1
    This is a really nice design pattern. Housing the `useState` calls within a separate function can help to keep components light weight. Thank you very much. – ICW Feb 17 '21 at 18:14
  • @89n3ur0n everyone should be using functional components if at all possible – ICW Feb 17 '21 at 18:15
  • 1
    to use in gatsby/next with SSR you need to stop the getWindowDimensions function being called in node. So remove it from useState and put it in another useEffect: const [windowDimensions, setWindowDimensions] = useState([0, 0]); useEffect(() => { setWindowDimensions(getWindowDimensions()); }, []); – amcc Jun 10 '21 at 21:53
  • Made an SSR ready typescript version of this snippet for anyone that wants it: https://pastebin.com/cCycfwaL – ryanovas Dec 21 '21 at 02:45
  • 1
    Is there a performance concern here? just noticed that this causes a re-render of the component which you use it in (and children) once for each pixel step, effectively 1000s of times as you resize the screen back and forth. – zing Mar 06 '23 at 15:21
  • For everyone coming late to the party: You can use the hook from react-native itself: `import {useWindowDimensions} from 'react-native';` – RaideR Apr 12 '23 at 16:16
  • 1
    The second example was great, but unfortunately I ran into an infinite loop with the react 18 implementation. Are there any issues with this code? https://tsplay.dev/mZJQem – Lauro235 Aug 20 '23 at 20:58
  • Also getting the same issue as @Lauro235 when using `useSyncExternalStore`, always returning a new object in `getSnapshot()` causes an infinite render loop but I can't figure out a way around it. Tried using `useMemo` and the page renders but still get the error once: "The result of getSnapshot should be cached to avoid an infinite loop" – iBobb Sep 02 '23 at 10:54
292

This answer is similar to Jabran Saeed's, except it handles window resizing as well. I got it from here.

constructor(props) {
  super(props);
  this.state = { width: 0, height: 0 };
  this.updateWindowDimensions = this.updateWindowDimensions.bind(this);
}

componentDidMount() {
  this.updateWindowDimensions();
  window.addEventListener('resize', this.updateWindowDimensions);
}

componentWillUnmount() {
  window.removeEventListener('resize', this.updateWindowDimensions);
}

updateWindowDimensions() {
  this.setState({ width: window.innerWidth, height: window.innerHeight });
}
speckledcarp
  • 6,196
  • 4
  • 22
  • 22
  • 3
    You can remove `.bind(this)` from the callback arguments since it's already bound by the constructor. – Scymex Apr 28 '17 at 12:28
  • 1
    Nitpick: code in constructor should probably be `this.state = { width: 0, height: 0 };` so that state vars don't change their types (if I understand correctly [window.innerWidth is integer](https://developer.mozilla.org/en-US/docs/Web/API/window/innerWidth)). Doesn't change anything except makes code easier to understand IMHO. Thanks for the answer! – johndodo Jan 05 '18 at 07:01
  • 8
    Why not `this.state = { width: window.innerWidth, height: window.innerHeight };` to start? – Gerbus Jan 28 '18 at 17:57
  • @Gerbus : +1. This is what made it work for me on initial page load. – Alan C. S. Mar 28 '18 at 00:31
  • 1
    Perhaps it's not the best idea to, use a callback to target the window's resize event and then re-target the global window object inside the callback. For performance, readability and convention sake, I am going to update it to use the given event values. – GoreDefex May 30 '18 at 01:16
  • I would suggest finding another solution -- I've found that on Android phones (at least), once you click on input, window dimensions are updated & keyboard gets hidden almost instantly, making it impossible to type in anything. – Justas Sam Sep 07 '18 at 09:34
  • where you used `componentDidMount() {`, i had to use `componentWillMount() {` instead for it to work – Luke Schoen Jan 13 '20 at 23:00
  • For me, Jabran Saeed's answer does in fact work when I resize the browser window (Safari 13). – pfincent Mar 25 '20 at 03:19
96

I've just edited QoP's current answer to support SSR and use it with Next.js (React 16.8.0+):

/hooks/useWindowDimensions.js:

import { useState, useEffect } from 'react';

export default function useWindowDimensions() {

  const hasWindow = typeof window !== 'undefined';

  function getWindowDimensions() {
    const width = hasWindow ? window.innerWidth : null;
    const height = hasWindow ? window.innerHeight : null;
    return {
      width,
      height,
    };
  }

  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useEffect(() => {
    if (hasWindow) {
      function handleResize() {
        setWindowDimensions(getWindowDimensions());
      }

      window.addEventListener('resize', handleResize);
      return () => window.removeEventListener('resize', handleResize);
    }
  }, [hasWindow]);

  return windowDimensions;
}

/yourComponent.js:

import useWindowDimensions from './hooks/useWindowDimensions';

const Component = () => {
  const { height, width } = useWindowDimensions();
  /* you can also use default values or alias to use only one prop: */
  // const { height: windowHeight = 480 } useWindowDimensions();

  return (
    <div>
      width: {width} ~ height: {height}
    </div>
  );
}
giovannipds
  • 2,860
  • 2
  • 31
  • 39
  • 1
    I tried doing this with NextJS but it seems to only have the correct size after a screen resize. I assume it is because of nextJS server-side rendering. Do you have any ideas? – herohamp Jul 24 '20 at 15:09
  • @herohamp hi! I'm very sorry my late reply, can you provide us an example? It shouldn't, at least, I think. It's supposed to get the window dimensions right after entering on the component / page as well. Yes, it won't run on server side, since window is a global variable available only when the DOM's loaded (that's why we check it with typeof). On server-side will always show null but when enters in front side must show a value different than null. – giovannipds Aug 01 '20 at 20:39
  • @herohamp You should create another `useEffect` hook. Unfortunately this answer will never correctly set the size without resizing. And more unfortunately it won't let me edit it. Do `useEffect(()=>setWindowDimensions(getWindowDimensions()), [])` and it will work correctly – ICW Jan 15 '21 at 14:52
  • 1
    This answer does not work because it will not set the size without resizing. See my previous comment please make the edit – ICW Jan 15 '21 at 14:53
  • @IsaacCWay I'm not sure if I understand you, this line `const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());` should be setting the initial `width`/`height` dimensions, it calls `getWindowDimensions()` - but I'm not able to test this right now. – giovannipds Jan 20 '21 at 13:34
  • 1
    @giovannipds sorry I must have misread it this works – ICW Jan 20 '21 at 14:41
  • I just tried your custom hooks @giovannipds in my NextJS project. It works BUT it's also triggering a warning: https://share.getcloudapp.com/llunPllO (there is a difference between what the server sees and what the FE see) I have tried many different approach to fix the problem, including trying to create another useeffect around it without luck :-( – Mr Washington Jan 21 '21 at 10:01
  • @MrWashington I'm not sure if you're understanding what you're trying to accomplish. `window` will never be available on the server. That's why we have `const hasWindow = typeof window !== 'undefined';`. Also, I know they've implemented this kind of messages but I didn't try the hook after they did it, so I'm not sure if something needs to be changed for that. Anyway, don't take my code as a solution for all cases, it was, at the time I wrote it. Use it to think and adapt for what you need. – giovannipds Jan 21 '21 at 22:21
  • @MrWashington and one more thing, if it's a `warning` (normally in yellow), it would be ok - not an error (normally in red, as shown above). – giovannipds Jan 21 '21 at 22:22
  • @MrWashington just to complement it, make sure you're not trying to render `width` or `height` on the server side, that may be the reason you're getting that warning. But it's just a guess. – giovannipds Jan 21 '21 at 22:24
  • 2
    Hi Giovani, thanks for your answer. Yes, I understand what your code is doing. My point was to flag to others that that with the latest versions of Next it will trigger a warning (and I agree with you, it still works, it's just a warning). I cannot find anywhere in the doc a way to: 1. Ignore this warning easily in Next. 2. Tweak the code so it doesn't trigger it. For the later if you have any pointer let me know ;-) – Mr Washington Jan 22 '21 at 10:54
  • 1
    @MrWashington if you could, make a repo for example / test case and I'll check with you. – giovannipds Jan 22 '21 at 14:10
  • 1
    Thanks for looking at it, really appreciate! I just created the branch `windowDimension` here https://github.com/aegiz/next-ts-styledcomponents-boilerplate/tree/windowDimension – Mr Washington Jan 22 '21 at 16:05
  • Ok I figured it out! Here is the correct implementation https://dev.to/adrien/creating-a-custom-react-hook-to-get-the-window-s-dimensions-in-next-js-135k TLDR: with NextJS stuff that run only on the FE should be enclose in a useEffect hook – Mr Washington Feb 15 '21 at 17:26
  • 1
    @MrWashington hey! I'm so sorry I couldn't give you attention. Like I said, this is probably something very simple. Check out this gist, please: https://gist.github.com/giovannipds/fecf287a2331ae97c4a9cef82f46b4ed - it may solve your needs with my version just a tweaked a little. This way it'll solve that `useEffect` problem you've mentioned, probably (didn't test it). – giovannipds Feb 15 '21 at 20:23
  • this is only working for me after resizing the window. @herohamp did you ever figure out a workaround? – bze12 Sep 04 '21 at 04:48
  • Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Modules are automatically in strict mode.ts(1252) – János May 28 '22 at 17:39
68
class AppComponent extends React.Component {

  constructor(props) {
    super(props);
    this.state = {height: props.height};
  }

  componentWillMount(){
    this.setState({height: window.innerHeight + 'px'});
  }

  render() {
    // render your component...
  }
}

Set the props

AppComponent.propTypes = {
 height:React.PropTypes.string
};

AppComponent.defaultProps = {
 height:'500px'
};

viewport height is now available as {this.state.height} in rendering template

Community
  • 1
  • 1
Jabran Saeed
  • 5,760
  • 3
  • 21
  • 37
  • 18
    This solution doesn't update if the browser window is resized – speckledcarp Feb 09 '17 at 15:16
  • 1
    FYI, updating the state after a component mount will trigger a second render() call and can lead to property/layout thrashing. https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-did-mount-set-state.md – Haukur Kristinsson Apr 15 '17 at 08:14
  • 1
    @HaukurKristinsson how to overcome this? – richardaum Jun 07 '17 at 19:11
  • 1
    @JabranSaeed why not just go ahead and set the height on the constructor instead of updating it on mount? If you need to take props into consideration you can default the value to it like this: `height: window.innerHeight || props.height`. This will not only simplify the code but also removes unnecessary state changes. – JohnnyQ Jul 13 '17 at 05:31
  • `componentWillMount` is no longer recommended, see https://reactjs.org/docs/react-component.html#unsafe_componentwillmount – holmberd Apr 18 '19 at 18:28
40

I found a simple combo of QoP and speckledcarp's answer using React Hooks and resizing features, with slightly less lines of code:

const [width, setWidth]   = useState(window.innerWidth);
const [height, setHeight] = useState(window.innerHeight);
const updateDimensions = () => {
    setWidth(window.innerWidth);
    setHeight(window.innerHeight);
}
useEffect(() => {
    window.addEventListener("resize", updateDimensions);
    return () => window.removeEventListener("resize", updateDimensions);
}, []);

Oh yeah make sure that the resize event is in double quotes, not single. That one got me for a bit ;)

HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
J.E.C.
  • 2,616
  • 2
  • 18
  • 21
22

@speckledcarp 's answer is great, but can be tedious if you need this logic in multiple components. You can refactor it as an HOC (higher order component) to make this logic easier to reuse.

withWindowDimensions.jsx

import React, { Component } from "react";

export default function withWindowDimensions(WrappedComponent) {
    return class extends Component {
        state = { width: 0, height: 0 };

        componentDidMount() {
            this.updateWindowDimensions();
            window.addEventListener("resize", this.updateWindowDimensions);
        }

        componentWillUnmount() {
            window.removeEventListener("resize", this.updateWindowDimensions);
        }

        updateWindowDimensions = () => {
            this.setState({ width: window.innerWidth, height: window.innerHeight });
        };

        render() {
            return (
                <WrappedComponent
                    {...this.props}
                    windowWidth={this.state.width}
                    windowHeight={this.state.height}
                    isMobileSized={this.state.width < 700}
                />
            );
        }
    };
}

Then in your main component:

import withWindowDimensions from './withWindowDimensions.jsx';

class MyComponent extends Component {
  render(){
    if(this.props.isMobileSized) return <p>It's short</p>;
    else return <p>It's not short</p>;
}

export default withWindowDimensions(MyComponent);

You can also "stack" HOCs if you have another you need to use, e.g. withRouter(withWindowDimensions(MyComponent))

Edit: I would go with a React hook nowadays (example above here), as they solve some of the advanced issues with HOCs and classes

James L.
  • 12,893
  • 4
  • 49
  • 60
19

Using Hooks:

using useLayoutEffect is more efficient here:

import { useState, useLayoutEffect } from 'react';

function getWindowDimensions() {
  const { innerWidth: width, innerHeight: height } = window;
  return {
    width,
    height
  };
}

export default function useWindowDimensions() {
  const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

  useLayoutEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowDimensions;
}

usage:

const { height, width } = useWindowDimensions();
foad abdollahi
  • 1,733
  • 14
  • 32
18

with a little typescript

import { useState, useEffect } from 'react';

interface WindowDimentions {
    width: number;
    height: number;
}

function getWindowDimensions(): WindowDimentions {
    const { innerWidth: width, innerHeight: height } = window;

    return {
      width,
      height
    };
  }
  
  export default function useWindowDimensions(): WindowDimentions {
    const [windowDimensions, setWindowDimensions] = useState<WindowDimentions>(
      getWindowDimensions()
    );
  
    useEffect(() => {
      function handleResize(): void {
        setWindowDimensions(getWindowDimensions());
      }
  
      window.addEventListener('resize', handleResize);

      return (): void => window.removeEventListener('resize', handleResize);
    }, []);
  
    return windowDimensions;
  }
Matthew Barnden
  • 516
  • 1
  • 6
  • 15
18

Adding this for diversity and clean approach.

This code uses functional style approach. I have used onresize instead of addEventListener as mentioned in other answers.

import { useState, useEffect } from "react";

export default function App() {
  const [size, setSize] = useState({
    x: window.innerWidth,
    y: window.innerHeight
  });
  const updateSize = () =>
    setSize({
      x: window.innerWidth,
      y: window.innerHeight
    });
  useEffect(() => (window.onresize = updateSize), []);
  return (
    <>
      <p>width is : {size.x}</p>
      <p>height is : {size.y}</p>
    </>
  );
}
Aklesh Sakunia
  • 321
  • 2
  • 6
  • An small update if you get an error like: "window is not defined". Set the initial value of the state x and y to 0 and all works. – NicholasWM Oct 13 '21 at 11:06
9

I just spent some serious time figuring some things out with React and scrolling events / positions - so for those still looking, here's what I found:

The viewport height can be found by using window.innerHeight or by using document.documentElement.clientHeight. (Current viewport height)

The height of the entire document (body) can be found using window.document.body.offsetHeight.

If you're attempting to find the height of the document and know when you've hit the bottom - here's what I came up with:

if (window.pageYOffset >= this.myRefII.current.clientHeight && Math.round((document.documentElement.scrollTop + window.innerHeight)) < document.documentElement.scrollHeight - 72) {
        this.setState({
            trueOrNot: true
        });
      } else {
        this.setState({
            trueOrNot: false
        });
      }
    }

(My navbar was 72px in fixed position, thus the -72 to get a better scroll-event trigger)

Lastly, here are a number of scroll commands to console.log(), which helped me figure out my math actively.

console.log('window inner height: ', window.innerHeight);

console.log('document Element client hieght: ', document.documentElement.clientHeight);

console.log('document Element scroll hieght: ', document.documentElement.scrollHeight);

console.log('document Element offset height: ', document.documentElement.offsetHeight);

console.log('document element scrolltop: ', document.documentElement.scrollTop);

console.log('window page Y Offset: ', window.pageYOffset);

console.log('window document body offsetheight: ', window.document.body.offsetHeight);

Whew! Hope it helps someone!

Vega
  • 27,856
  • 27
  • 95
  • 103
thielr7
  • 327
  • 3
  • 11
9

Good day,

I know I am late to this party, but let me show you my answer.

const [windowSize, setWindowSize] = useState(null)

useEffect(() => {
    const handleResize = () => {
        setWindowSize(window.innerWidth)
    }

    window.addEventListener('resize', handleResize)

    return () => window.removeEventListener('resize', handleResize)
}, [])

for further details please visit https://usehooks.com/useWindowSize/

Aljohn Yamaro
  • 2,629
  • 25
  • 22
  • 3
    Should you call handleResize() within the effect so the original browser window size is set? Also window.innerHeight will get the height – Dylan w Aug 11 '20 at 06:01
5

You can create custom hooks like this: useWindowSize()

import { useEffect, useState } from "react";
import { debounce } from "lodash";

const getWindowDimensions = () => {
  const { innerWidth: width, innerHeight: height } = window;
  return { width, height };
};

export function useWindowSize(delay = 0) {
  const [windowDimensions, setWindowDimensions] = useState(
    getWindowDimensions()
  );

  useEffect(() => {
    function handleResize() {
      setWindowDimensions(getWindowDimensions());
    }
    const debouncedHandleResize = debounce(handleResize, delay);
    window.addEventListener("resize", debouncedHandleResize);
    return () => window.removeEventListener("resize", debouncedHandleResize);
  }, [delay]);

  return windowDimensions;
}
Jason Jin
  • 1,739
  • 14
  • 21
4
// just use (useEffect). every change will be logged with current value
import React, { useEffect } from "react";

export function () {
  useEffect(() => {
    window.addEventListener('resize', () => {
      const myWidth  = window.innerWidth;
      console.log('my width :::', myWidth)
   })
  },[window])

  return (
    <>
      enter code here
   </>
  )
}
Joabe
  • 49
  • 1
  • 1
    Welcome to Stack Overflow. Code dumps without any explanation are rarely helpful. Stack Overflow is about learning, not providing snippets to blindly copy and paste. Please [edit] your question and explain how it works better than what the OP provided. – ChrisGPT was on strike May 13 '20 at 23:31
  • 2
    Careful, this code never removes the event listener it creates. https://stackoverflow.com/a/36862446/867600 is a better hook approcach. – Christophe Cadilhac Jul 29 '20 at 08:26
2

Answers by @speckledcarp and @Jamesl are both brilliant. In my case, however, I needed a component whose height could extend the full window height, conditional at render time.... but calling a HOC within render() re-renders the entire subtree. BAAAD.

Plus, I wasn't interested in getting the values as props but simply wanted a parent div that would occupy the entire screen height (or width, or both).

So I wrote a Parent component providing a full height (and/or width) div. Boom.

A use case:

class MyPage extends React.Component {
  render() {
    const { data, ...rest } = this.props

    return data ? (
      // My app uses templates which misbehave badly if you manually mess around with the container height, so leave the height alone here.
      <div>Yay! render a page with some data. </div>
    ) : (
      <FullArea vertical>
        // You're now in a full height div, so containers will vertically justify properly
        <GridContainer justify="center" alignItems="center" style={{ height: "inherit" }}>
          <GridItem xs={12} sm={6}>
            Page loading!
          </GridItem>
        </GridContainer>
      </FullArea>
    )

Here's the component:

import React, { Component } from 'react'
import PropTypes from 'prop-types'

class FullArea extends Component {
  constructor(props) {
    super(props)
    this.state = {
      width: 0,
      height: 0,
    }
    this.getStyles = this.getStyles.bind(this)
    this.updateWindowDimensions = this.updateWindowDimensions.bind(this)
  }

  componentDidMount() {
    this.updateWindowDimensions()
    window.addEventListener('resize', this.updateWindowDimensions)
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.updateWindowDimensions)
  }

  getStyles(vertical, horizontal) {
    const styles = {}
    if (vertical) {
      styles.height = `${this.state.height}px`
    }
    if (horizontal) {
      styles.width = `${this.state.width}px`
    }
    return styles
  }

  updateWindowDimensions() {
    this.setState({ width: window.innerWidth, height: window.innerHeight })
  }

  render() {
    const { vertical, horizontal } = this.props
    return (
      <div style={this.getStyles(vertical, horizontal)} >
        {this.props.children}
      </div>
    )
  }
}

FullArea.defaultProps = {
  horizontal: false,
  vertical: false,
}

FullArea.propTypes = {
  horizontal: PropTypes.bool,
  vertical: PropTypes.bool,
}

export default FullArea
thclark
  • 4,784
  • 3
  • 39
  • 65
2

I've updated the code with a slight variation by wrapping the getWindowDimensions function in useCallback

import { useCallback, useLayoutEffect, useState } from 'react';

export default function useWindowDimensions() {

    const hasWindow = typeof window !== 'undefined';

    const getWindowDimensions = useCallback(() => {
        const windowWidth = hasWindow ? window.innerWidth : null;
        const windowHeight = hasWindow ? window.innerHeight : null;

        return {
            windowWidth,
            windowHeight,
        };
    }, [hasWindow]);

    const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());

    useLayoutEffect(() => {
        if (hasWindow) {
            function handleResize() {
                setWindowDimensions(getWindowDimensions());
            }

            window.addEventListener('resize', handleResize);
            return () => window.removeEventListener('resize', handleResize);
        }
    }, [getWindowDimensions, hasWindow]);

    return windowDimensions;
}
Gunzz
  • 21
  • 1
2

Here you have the most voted answer wrapped in a node package (tested, typescript) ready to use.

Install:

npm i @teambit/toolbox.react.hooks.get-window-dimensions

Usage:

import React from 'react';
import { useWindowDimensions } from '@teambit/toolbox.react.hooks.get-window-dimensions';

const MyComponent = () => {
  const { height, width } = useWindowDimensions();

  return (
    <>
      <h1>Window size</h1>
      <p>Height: {height}</p>
      <p>Width: {width}</p>
    </>
  );
};
Jonatan Kruszewski
  • 1,027
  • 3
  • 23
2

I recommand the usage of the useSyncExternalStore

import { useSyncExternalStore } from "react";

const store = {
  size: {
    height: undefined,
    width: undefined
  }
};

export default function ChatIndicator() {
  const { height, width } = useSyncExternalStore(subscribe, getSnapshot);
  return (
    <h1>
      {width} {height}
    </h1>
  );
}

function getSnapshot() {
  if (
    store.size.height !== window.innerHeight ||
    store.size.width !== window.innerWidth
  ) {
    store.size = { height: window.innerHeight, width: window.innerWidth };
  }
  return store.size;
}

function subscribe(callback) {
  window.addEventListener("resize", callback);
  return () => {
    window.removeEventListener("resize", callback);
  };
}

If you want try it : https://codesandbox.io/s/vibrant-antonelli-5cecpm

Hagatopaxi
  • 21
  • 1
1

Simple way to keep current dimensions in the state, even after window resize:

//set up defaults on page mount
componentDidMount() {
  this.state = { width: 0, height: 0 };
  this.getDimensions(); 

  //add dimensions listener for window resizing
  window.addEventListener('resize', this.getDimensions); 
}

//remove listener on page exit
componentWillUnmount() {
  window.removeEventListener('resize', this.getDimensions); 
}

//actually set the state to the window dimensions
getDimensions = () => {
  this.setState({ width: window.innerWidth, height: window.innerHeight });
  console.log(this.state);
}
GavinBelson
  • 2,514
  • 25
  • 36
1

This is how you can implement it and get the window width and height on real time inside React functional components:

import React, {useState, useEffect} from 'react' 
const Component = () => {
  const [windowWidth, setWindowWidth] = useState(0)
  const [windowHeight, setWindowHeight] = useState(0)
  
  useEffect(() => {
    window.addEventListener('resize', e => {
      setWindowWidth(window.innerWidth);
    });
  }, [window.innerWidth]);

  useEffect(() => {
    window.addEventListener('resize', e => {
      setWindowHeight(window.innerHeight);
    });
  }, [window.innerHeight]);

  return(
    <h3>Window width is: {windowWidth} and Height: {windowHeight}</h3>
  )
}
Yaser AZ
  • 384
  • 1
  • 5
1

I used the most upvoted answer, but useSyncExternalStore caused an infinite loop of maximum update exceeded when getSnapshot returns a different value each time (even if the properties width and height are the same, a new object is created each time), so I changed to cache the last value and use it if the width and the height are the same:

import { useSyncExternalStore } from 'react';

export function useWindowDimensions() {
    // the 3rd parameter is optional and only needed for server side rendering
    return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
}

const subscribe = (
    callback: (this: Window, ev: WindowEventMap['resize']) => unknown,
) => {
    window.addEventListener('resize', callback);
    return () => window.removeEventListener('resize', callback);
};

export interface WindowSizes {
    width: number;
    height: number;
}

const getSnapshot = ((value: WindowSizes | undefined) => () => {
    if (
        !value ||
        value.width !== window.innerWidth ||
        value.height !== window.innerHeight
    ) {
        value = { width: window.innerWidth, height: window.innerHeight };
    }

    return value;
})(undefined);

const getServerSnapshot = (
    (
        value = {
            width: 0,
            height: 0,
        },
    ) =>
    () => {
        return value;
    }
)();
Lucas Basquerotto
  • 7,260
  • 2
  • 47
  • 61
0

You can also try this:

constructor(props) {
        super(props);
        this.state = {height: props.height, width:props.width};
      }

componentWillMount(){
          console.log("WINDOW : ",window);
          this.setState({height: window.innerHeight + 'px',width:window.innerWidth+'px'});
      }

render() {
        console.log("VIEW : ",this.state);
}
Shubham Verma
  • 8,783
  • 6
  • 58
  • 79
0

It is simple to get with useEffect

useEffect(() => {
    window.addEventListener("resize", () => {
        updateDimention({ 
            ...dimension, 
            width: window.innerWidth, 
            height: window.innerHeight 
        });
        console.log(dimension);
    })
})
bren
  • 4,176
  • 3
  • 28
  • 43
0

As answer from: bren but hooking useEffect to [window.innerWidth]

const [dimension, updateDimention] = useState();
  
  useEffect(() => {
    window.addEventListener("resize", () => {
        updateDimention({ 
            ...dimension, 
            width: window.innerWidth, 
            height: window.innerHeight 
        });
       
    })
},[window.innerWidth]);

 console.log(dimension);
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Dec 02 '21 at 01:11
0

React native web has a useWindowDimensions hook that is ready to be used:

    import { useWindowDimensions } from "react-native";
    const dimensions = useWindowDimensions()
pl709
  • 19
  • 1
  • 2
0

There is a package with 93.000+ downloads, named useWindowSize()

npm i @react-hook/window-size

import {
  useWindowSize,
  useWindowWidth,
  useWindowHeight,
} from '@react-hook/window-size'

const Component = (props) => {
  const [width, height] = useWindowSize()
  const onlyWidth = useWindowWidth()
  const onlyHeight = useWindowHeight()
...
}

docs

Fotios Tsakiris
  • 1,310
  • 1
  • 18
  • 24
0

A combination of @foad abdollahi and @giovannipds answers helped me to find a solution using custom hooks with useLayoutEffect in Nextjs.

function getWindowDimensions() {
    const { innerWidth: width, innerHeight: height } = window;
    return {
      width,
      height,
    };
  }

  function useWindowDimensions() {
    const [windowDimensions, setWindowDimensions] = useState(
      getWindowDimensions()
    );

    useLayoutEffect(() => {
      const isWindow = typeof window !== 'undefined';
      function handleResize() {
        setWindowDimensions(getWindowDimensions());
      }

      isWindow && window.addEventListener('resize', handleResize);
      console.log(windowDimensions);
      return () =>
        isWindow && window.removeEventListener('resize', handleResize);
    }, [windowDimensions]);

    return windowDimensions;
  }
programandoconro
  • 2,378
  • 2
  • 18
  • 33
0

Same answer with @QoP but implemented in Remix.run

import {useState, useEffect} from 'react';

function getWindowDimensions() {
  if (typeof window !== 'undefined') {
    const {innerWidth: width, innerHeight: height} = window;
    return {
      width,
      height,
    };
  } else {
    return null; // or return an empty object {}
  }
}

export default function useWindowDimensions() {
  const [windowDimensions, setWindowDimensions] = useState(
    getWindowDimensions() || {width: 0, height: 0},
  );

  useEffect(() => {
    function handleResize() {
      const dimensions = getWindowDimensions();
      if (dimensions) {
        setWindowDimensions(dimensions);
      }
    }

    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return windowDimensions;
}
0

Final code

import React, { useState, useEffect } from 'react'

export default function App() {
    const [screenSize, setScreenSize] = useState(getCurrentDimension());

    function getCurrentDimension(){
        return {
            width: window.innerWidth,
            height: window.innerHeight
        }
    }
  
    useEffect(() => {
            const updateDimension = () => {
                setScreenSize(getCurrentDimension())
            }
            window.addEventListener('resize', updateDimension);
    
        
            return(() => {
                window.removeEventListener('resize', updateDimension);
            })
    }, [screenSize])
    return (
        <div>
            <ul>
                <li>Width: <strong>{screenSize.width}</strong></li>
                <li>Height: <strong>{screenSize.height}</strong></li>
            </ul>    
        </div>
    )
}