Search code examples
reactjsreact-hooksnext.jsobservers

React: how to calculate the height of a div based on its width?


I have to find the height of a div based on its width.

Here is my try:

import React from 'react';
import Image from "next/image";
import DivHeightfromWidth from "src/components/Dimension/divheight.jsx";

const GalleryTab = ({ image }) => {
    const targetRef = React.useRef(null);
    const calcHeight = DivHeightfromWidth(targetRef, 11);

    return <div ref={targetRef} style={{ height: calcHeight, width: "100%" }}>
        <Image
            src={image.src}
            alt={image?.alt}
            layout='fill'
            objectFit='contain'
        />
    </div> 
}
export default GalleryTab;

I set a ref (targetRef) to my div and call DivHeightfromWidth function.

This is where new Observer is set:

import React from "react";

const DivHeightfromWidth = (elRef, ratio) => {
    const [width, setWidth] = React.useState(0);
    var height = 0;

    const observer = React.useRef(
        new ResizeObserver(entries => {
            // Only care about the first element, we expect one element ot be watched
            const { width } = entries[0].contentRect;

            setWidth(width)

        })
    );

    React.useEffect(() => {
        if (elRef != null && elRef.current) {
            if (observer != null && observer.current) {
                observer.current.observe(elRef.current);
                if (observer.current.observe(elRef.current) != null) {
                    return () => {
                        observer.current.unobserve(elRef.current);
                    };
                }

            }

        }

    }, [elRef, observer]);

    if (ratio === 169)
        height = width * 16 / 9;
    else
        height = width;

    return height;
}

export default DivHeightfromWidth;

I'm getting this error: ResizeObserver is not defined.

Moreover I tried to use useEffect in GalleryTab for calcHeight but got a different error: Invalid hook call. Hooks can only be called inside of the body of a function component.

Do you have any ideas on how to make it work?


Solution

  • Here is my simple solution using clientWidth of my ref within useEffect hook:

    const GalleryTab = ({ image }) => {
        const [height, setHeight] = React.useState(0)
        const ref = React.useRef([])
    
        React.useEffect(() => {
            setHeight(ref.current[0].clientWidth)
        }, [])
    
        return <div ref={ref} style={{ height: height, width: "100%" }}>
            <Image
                src={image.src}
                alt={image?.alt}
                layout='fill'
                objectFit='contain'
            />
        </div> 
    }
    export default GalleryTab;
    

    When you do setHeight, you can calculate any ratio, in this case is 1:1 so width and height have same dimension.