I'm creating a component and I need to get it's parent <div>
width and height. I'm using Hooks, so all my components are functions. I've read some examples using classes, but this won't apply to my component.
So I have this component:
export default function PlantationMap(props) {
<div className="stage-canvas">
<Stage
width={window.innerWidth * 0.5}
height={window.innerHeight * 0.5}
onWheel={handleWheel}
scaleX={stage.stageScale}
scaleY={stage.stageScale}
x={stage.stageX}
y={stage.stageY}
draggable
/ >
</div>
}
How could I get the <div>
height and width to use in <Stage width={} height={} />
?
Thank you very much in advance
Edit: I tried using the useRef()
hook, like this:
const div = useRef();
return (
<div ref={div}>
...
</div>
)
But I can't access the div.current
object
I think useCallback is what you want to use so you can get the width and height when it changes.
const [height, setHeight] = useState(null);
const [width, setWidth] = useState(null);
const div = useCallback(node => {
if (node !== null) {
setHeight(node.getBoundingClientRect().height);
setWidth(node.getBoundingClientRect().width);
}
}, []);
return (
<div ref={div}>
...
</div>
)
Declare a reference using useRef
hook and then read current.offsetHeight
and current.offsetWidth
properties.
Here is the code:
import React, { useEffect, useRef } from 'react';
const PlantationMap = (props) => {
const stageCanvasRef = useRef(null);
// useEffect will run on stageCanvasRef value assignment
useEffect( () => {
// The 'current' property contains info of the reference:
// align, title, ... , width, height, etc.
if(stageCanvasRef.current){
let height = stageCanvasRef.current.offsetHeight;
let width = stageCanvasRef.current.offsetWidth;
}
}, [stageCanvasRef]);
return(
<div className = "stage-canvas" ref = {stageCanvasRef}>
<Stage
width={window.innerWidth * 0.5}
height={window.innerHeight * 0.5}
onWheel={handleWheel}
scaleX={stage.stageScale}
scaleY={stage.stageScale}
x={stage.stageX}
y={stage.stageY}
draggable
/ >
</div>);
}
export default PlantationMap;
to my knowledge if it is concerned with style can only be registered by:
<Stage style={{width:window.innerWidth * 0.5,height:width:window.innerWidth * 0.5}} />
You can make use of the built-inResizeObserver :
export default function PlantationMap(props) {
const [width, setWidth] = useState(100);
const [height, setHeight] = useState(100);
useEffect(() => {
const resizeObserver = new ResizeObserver((event) => {
// Depending on the layout, you may need to swap inlineSize with blockSize
// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize
setWidth(event[0].contentBoxSize[0].inlineSize);
setHeight(event[0].contentBoxSize[0].blockSize);
});
resizeObserver.observe(document.getElementById("div1"));
});
return (
<div id="div1" className="stage-canvas">
<Stage
width={width * 0.5}
height={height * 0.5}
onWheel={handleWheel}
scaleX={stage.stageScale}
scaleY={stage.stageScale}
x={stage.stageX}
y={stage.stageY}
draggable
/ >
</div>
);
}
I think ResizeObserver is the way to go as mentioned in the answer from Dan. I just wouldn't use the document.getElementById
. Either use useMeasure
from react-use or create everything on your own.
There are two scenarios:
To 1 - Reference directly accessible
In this case, you can create the reference with useRef
in the component and use it at resizeObserver.observe(demoRef.current)
.
import "./styles.css";
import React, { useEffect, useRef, useState } from "react";
const DisplaySize = ({ width, height }) => (
<div className="centered">
<h1>
{width.toFixed(0)}x{height.toFixed(0)}
</h1>
</div>
);
const Demo = () => {
const [width, setWidth] = useState(100);
const [height, setHeight] = useState(100);
const demoRef = useRef();
useEffect(() => {
const resizeObserver = new ResizeObserver((event) => {
// Depending on the layout, you may need to swap inlineSize with blockSize
// https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize
setWidth(event[0].contentBoxSize[0].inlineSize);
setHeight(event[0].contentBoxSize[0].blockSize);
});
if (demoRef) {
resizeObserver.observe(demoRef.current);
}
}, [demoRef]);
return (
<div ref={demoRef} className="App">
<DisplaySize width={width} height={height} />
</div>
);
}; //);
export default function App() {
return <Demo />;
}
To 2 - Reference of container not directly accessible:
This case is probably happening more often and requires slightly more code. You need to pass the reference from the parent to the child component with React.forwardRef
.
Demo code can be found below or in the following Codesandbox
Some words to the code:
const containerRef = useRef()
and use it at the main container with <div ref={containerRef}/>
. Under the hood it will do something like ref => containerRef.current=ref
Demo
component. Why not use React.createRef
?
That would work too but it would recreate the reference on every render of your App. Please have a look here for an explanation of the difference between useRef
and createRef
.
In short, use useRef
with functional components and use createRef
with class-based components.
const {useEffect, useRef, useState} = React; const DisplaySize = ({ width, height }) => ( <div className="centered"> <h1> {width.toFixed(0)}x{height.toFixed(0)} </h1> </div> ); const Demo = React.forwardRef((props, ref) => { const [width, setWidth] = useState(100); const [height, setHeight] = useState(100); useEffect(() => { const resizeObserver = new ResizeObserver((event) => { // Depending on the layout, you may need to swap inlineSize with blockSize // https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserverEntry/contentBoxSize setWidth(event[0].contentBoxSize[0].inlineSize); setHeight(event[0].contentBoxSize[0].blockSize); }); if (ref && ref.current) { resizeObserver.observe(ref.current); } }, [ref]); return <DisplaySize width={width} height={height} />; }); function App() { const containerRef = useRef(); return ( <div ref={containerRef} className="App"> <Demo ref={containerRef} /> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render( <App />, rootElement );
/* apply a natural box layout model to all elements, but allowing components to change */ html { box-sizing: border-box; } *, *:before, *:after { box-sizing: inherit; } html, body { margin: 0; padding: 0; }.App { position: absolute; top: 0; left: 0; width: 100%; height: 100%; overflow: hidden; font-family: sans-serif; text-align: center; border: 4px solid red; }.centered { display: flex; /* establish flex container */ flex-direction: column; /* make main axis vertical */ justify-content: center; /* center items vertically, in this case */ align-items: center; /* center items horizontally, in this case */ height: 100%; }
<script crossorigin src="https://unpkg.com/react@17/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script> <div id="root"></div>
There are also some useful hooks in React-use
that could help here.
useWindowSize
and useSize
look pretty similar but after looking at the source code the first one relies on the window.onresize
event and requires less code to implement.
useSize
will add an iframe below the current component ( z-index: -1
) to track the size with resize
event and requires more code. It also adds a little debounce with setTimeout
.
So use useWindowSize
if you just need the width/height to do some calculations on the first render and useSize
if you'd like to show that the size changed.
If you just need to get the window size useWindowSize is the way to go. They're doing it with onresize event with document.addEventlistener('resize', resizeHandler)
and checking innerWidth / innerHeight
Codesandbox Demo
To track an element size, useMeasure
can be used. It is using ResizeObserver
under the hood, so it's like the code above where ref
is the reference you'd like to track:
The first element returned by useMeasure
is the setRef
method. So you can do the following in your component:
const [setRef, { width, height }] = useMeasure();
useEffect(() => {
setRef(ref.current)
}, [])
Please have a look at the following Codesandbox .
If you want to track the size of a component useSize
could be used as mentioned in the docs . Codesandbox Demo useSize
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.