Get viewport/window height in ReactJS - javascript

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.

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

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

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

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

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

#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

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

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

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();

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!

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/

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

// 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
</>
)
}

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

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

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

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

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

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

It is simple to get with useEffect
useEffect(() => {
window.addEventListener("resize", () => {
updateDimention({
...dimension,
width: window.innerWidth,
height: window.innerHeight
});
console.log(dimension);
})
})

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

React native web has a useWindowDimensions hook that is ready to be used:
import { useWindowDimensions } from "react-native";
const dimensions = useWindowDimensions()

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

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

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

Related

How to update immediately with useEffect screen window width value, not only after browser is refreshed [duplicate]

I'm using this code to listen for resize events in a function component and rerender the component when the window is resized. The problem is, nothing ever gets printed out for either event listener, so I think I have a misunderstanding of how I'm using useEffect here.
const [dimensions, setDimensions] = React.useState({
width: window.innerWidth,
height: window.innerHeight,
});
useEffect(() => {
const handleResize = () => {
console.log(dimensions.width);
setDimensions({
width: window.innerWidth,
height: window.innerHeight,
});
window.addEventListener("load", handleResize, false);
window.addEventListener("resize", handleResize, false);
};
});
import { useState, useEffect } from "react";
// Usage
function App() {
const size = useWindowSize();
return (
<div>
{size.width}px / {size.height}px
</div>
);
}
// Hook
function useWindowSize() {
// Initialize state with undefined width/height so server and client renders match
// Learn more here: https://joshwcomeau.com/react/the-perils-of-rehydration/
const [windowSize, setWindowSize] = useState({
width: undefined,
height: undefined,
});
useEffect(() => {
// Handler to call on window resize
function handleResize() {
// Set window width/height to state
setWindowSize({
width: window.innerWidth,
height: window.innerHeight,
});
}
// Add event listener
window.addEventListener("resize", handleResize);
// Call handler right away so state gets updated with initial window size
handleResize();
// Remove event listener on cleanup
return () => window.removeEventListener("resize", handleResize);
}, []); // Empty array ensures that effect is only run on mount
return windowSize;
}
SOURCE
const [dimensions, setDimensions] = React.useState({
width: window.innerWidth,
height: window.innerHeight,
});
console.log(dimensions);
const handleResize = () => {
setDimensions({
width: window.innerWidth,
height: window.innerHeight,
});
}
React.useEffect(() => {
window.addEventListener("resize", handleResize, false);
}, []);
I found that the event listener on "resize" was not sufficient to populate the window dimensions in the initial load of the page. The following worked for me.
function getWindowDimensions() {
const {innerWidth: width, innerHeight: height} = window;
return {
width,
height
};
}
function useWindowDimensions() {
const defaultDim = {width: null, height: null}
const [windowDimensions, setWindowDimensions] = useState(defaultDim);
useEffect(() => {
setWindowDimensions(getWindowDimensions()) // Necessary to make sure dimensions are set upon initial load
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}

how to detect window is loaded in react

I have been trying to solve this problem for a couple days but can't seem to get it to work.
First, I have a custom hook to get if the client is viewing in mobile or desktop format.
that looks like this:
import { useState, useEffect } from "react";
function getWindowDimensions() {
if (typeof window !== "undefined") {
const { innerWidth: width, innerHeight: height } = window;
console.log("defined");
console.log(width < 768);
return width < 768 ? true : false;
}
console.log("undefined");
return true;
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
Now I am trying to use this in order to switch between a footer or a header style interaction on my website:
import useWindowDimensions from "hooks/useWindowDimensions";
import React, { useEffect } from "react";
import Footer from "./Footer";
import Header from "./Header";
export default function Shim(props) {
const isMobile = useWindowDimensions();
return (
<div>
{!isMobile && <Header {...props} />}
{isMobile && <Footer {...props} />}
</div>
);
}
I expected this to work perfectly, however it looks as if the the initial value is getting set when typeof window === "undefined", so, the mobile view is rendered in desktop size (if I resize the window after the site is loaded, it works as expected.) Would anyone be willing to lend me a hand as to how to get this to work appropriately?
Thank you!
I solve same problem with this context api hook.
import React, { createContext, useContext, useEffect, useState } from 'react';
export const SizeContext = createContext();
const SizeContextProvider = ({ children }) => {
const [width, setWidth] = useState(window.innerWidth);
const [isMobile, setIsMobile] = useState(true);
const [isDesktop, setIsDesktop] = useState(true);
function debounce(fn, ms) {
let timer;
return () => {
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
fn.apply(this, arguments);
}, ms);
};
}
useEffect(() => {
const debouncedHandleResize = debounce(() => {
setWidth(window.innerWidth);
}, 0);
window.addEventListener('resize', debouncedHandleResize);
return () => {
window.removeEventListener('resize', debouncedHandleResize);
};
});
useEffect(() => {
if (width <= 575) {
setIsMobile(true);
setIsDesktop(false);
} else if (width >= 576 && width < 767) {
setIsMobile(true);
setIsDesktop(false);
} else if (width >= 768 && width < 991) {
setIsMobile(false);
setIsDesktop(true);
} else if (width >= 992 && width < 1199) {
setIsMobile(false);
setIsDesktop(true);
} else {
setIsMobile(false);
setIsDesktop(true);
}
}, [width]);
return (
<SizeContext.Provider value={{ width, isDesktop, isMobile }}>
{children}
</SizeContext.Provider>
);
};
export const useSizeContext = () => useContext(SizeContext);
export default SizeContextProvider;
import context api use any component.
const App = () => {
return (
<SizeContextProvider>
<Device />
</SizeContextProvider>
)
}
Here Device Component use Context Api
const Device = () => {
const { isMobile, isDesktop } = useSizeContext();
return (
<div>
{isMobile && <h1> Small Device </h1>}
{isDesktop && <h1> Largest Device </h1>}
</div>
);
}

I have problem with detecting the width of the screen in React Project

I create Hook to detect the width & the height of Screen:
import { useState, useEffect } from "react";
const getWindowDimensions = () => {
const { innerWidth: width, innerHeight: height } = window;
return { width, height }
};
export function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(
getWindowDimensions()
);
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return windowDimensions;
}
and inside the component I called the useWindowDimensions hook and I console.log the width:
const { width } = useWindowDimensions();
console.log(width, "width");
and in the Console the width wasn't accurate at all:
Note: when I refresh the page it detects the width perfectly
any clue how can I fix this ?

useEffect hook not firing on orientation change

I am trying to change the height of a container, when in mobile landscape mode only. I am playing around in the developer tools to swap the orientation of a mobile device but it only works on the first render. I am new to react hooks so not sure if I am implementing it right.
The idea is that I am testing that once in landscape, if it's on mobile the height should be less than 450px (which is the check I am doing for the if statement)
Could someone point me in the right direction, please?
Thanks!
const bikeImageHeight = () => {
const windowViewportHeight = window.innerHeight;
const isLandscape = window.orientation === 90 || window.orientation === -90;
let bikeImgHeight = 0;
if (windowViewportHeight <= 450 && isLandscape) {
bikeImgHeight = windowViewportHeight - 50;
}
return bikeImgHeight;
};
useEffect(() => {
bikeImageHeight();
window.addEventListener("resize", bikeImageHeight);
return () => {
window.removeEventListener("resize", bikeImageHeight);
};
}, []);
The useEffect hook is not expected to fire on orientation change. It defines a callback that will fire when the component re-renders. The question then is how to trigger a re-render when the screen orientation changes. A re-render occurs when there are changes to a components props or state.
Lets make use of another related stackoverflow answer to build a useWindowDimensions hook. This allows us to hook into the windows size as component state so any changes will cause a re-render.
useWindowDimensions.js
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;
}
You can then use that hook in your component. Something like:
BikeImage.js
import React from 'react'
import useWindowDimensions from './useWindowDimensions'
export default () => {
const windowDimensions = useWindowDimensions();
// Define these helper functions as you like
const width = getImageWidth(windowDimensions.width)
const height = getImageHeight(windowDimensions.height)
// AppImage is a component defined elsewhere which takes
// at least width, height and src props
return <AppImage width={width} height={height} src="..." .../>
}
Here is a custom hook that fires on orientation change,
import React, {useState, useEffect} from 'react';
// Example usage
export default () => {
const orientation = useScreenOrientation();
return <p>{orientation}</p>;
}
function useScreenOrientation() {
const [orientation, setOrientation] = useState(window.screen.orientation.type);
useEffect(() => {
const handleOrientationChange= () => setOrientation(window.screen.orientation.type);
window.addEventListener('orientationchange', handleOrientationChange);
return () => window.removeEventListener('orientationchange', handleOrientationChange);
}, []);
return orientation;
}
Hope this takes you to the right direction.
You need to trigger a re-render, which can be done by setting state inside of your bikeImageHeight.
const [viewSize, setViewSize] = useState(0)
const bikeImageHeight = () => {
const windowViewportHeight = window.innerHeight;
const isLandscape = window.orientation === 90 || window.orientation === -90;
let bikeImgHeight = 0;
if (windowViewportHeight <= 450 && isLandscape) {
bikeImgHeight = windowViewportHeight - 50;
}
setViewSize(bikeImgHeight)
return bikeImgHeight;
};
And per the comments conversation, here's how you'd use debounce:
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
const YourComponent = () => {
const bikeImageHeight = () => {
const windowViewportHeight = window.innerHeight;
const isLandscape = window.orientation === 90 || window.orientation === -90;
let bikeImgHeight = 0;
if (windowViewportHeight <= 450 && isLandscape) {
bikeImgHeight = windowViewportHeight - 50;
}
setViewSize(bikeImgHeight)
return bikeImgHeight;
};
const debouncedBikeHeight = debounce(bikeImageHeight, 200)
useEffect(() => {
bikeImageHeight();
window.addEventListener("resize", debouncedBikeHeight);
return () => {
window.removeEventListener("resize", debouncedBikeHeight);
};
}, []);
return <div>some jsx</div>
}
Example debounce taken from here: https://davidwalsh.name/javascript-debounce-function

How to get the height of a react.element

I'm dynamically rendering a list of Symbol(react.element) by mapping into an array and placing each of its elements HTML tags. My question is therefore: how can I get the height of each of the rendered Symbol(react.element)? This seems not to be in the Symbol(react.element)'s object.
Thanks in advance for your help
Actually, if you are using Functional Components, would be better to isolate this resize logic in a custom hook instead of leave it inside the component. You can create a custom hook like this:
const useResize = (myRef) => {
const [width, setWidth] = useState(0)
const [height, setHeight] = useState(0)
const handleResize = () => {
setWidth(myRef.current.offsetWidth)
setHeight(myRef.current.offsetHeight)
}
useEffect(() => {
myRef.current && myRef.current.addEventListener('resize', handleResize)
return () => {
myRef.current.removeEventListener('resize', handleResize)
}
}, [myRef])
return { width, height }
}
and then you can use it like:
const MyComponent = () => {
const componentRef = useRef()
const { width, height } = useResize(componentRef)
return (
<div ref={componentRef}>
<p>width: {width}px</p>
<p>height: {height}px</p>
<div/>
)
}
class MyComponent extends Component {
constructor(props){
super(props)
this.myDiv = React.createRef()
}
componentDidMount () {
console.log(this.myDiv.current.offsetHeight)
}
render () {
return (
<div ref={this.myDiv}>element</div>
)
}
}
A modified version of Marcos answer.
I've placed a rendering bool to make sure all data is rendered before placing the height and width. This is to be sure that the height is calculated with all required elements in place instead of risking receiving an incorrect height and width.
useResize hook placed in a separate folder:
import { useState, useEffect, useCallback } from 'react';
export const useResize = (myRef: React.MutableRefObject<any>, rendering: boolean) => {
const [width, setWidth] = useState(0);
const [height, setHeight] = useState(0);
const handleResize = useCallback(() => {
setWidth(myRef.current.offsetWidth);
setHeight(myRef.current.offsetHeight);
}, [myRef]);
useEffect(() => {
if (!rendering) {
myRef.current && myRef.current.addEventListener('resize',
handleResize(), { once: true });
}
}, [myRef, handleResize, rendering]);
return { width, height };
Example of usage:
const MyComponent = ({ A, B }) => {
// A and B is data that is required in component
const componentRef = useRef()
const { width, height } = useResize(componentRef, !A || !B)
if (!A || !B) return;
return (
<div ref={componentRef}>
<p>{A} {width}px</p>
<p>{B} {height}px</p>
<div/>
)
}
const componentRef = useRef(null)
and div ref={componentRef}

Categories

Resources