Home > Enterprise >  Issue when designing a function to retrieve the document height and width
Issue when designing a function to retrieve the document height and width

Time:01-29

I'm currently having an issue with the function that I've created. Ideally it would retrieve the window.document.body.offsetHeight as soon as it's active, however the function won't work as intended if I don't start with window.innerHeight. I would like the entire document height, not the viewport height, hence the use of window.document.body.offsetHeight. However the function outright doesn't work if I use window.document.body.offsetHeight in the first constant statement.

function useWindowSize() {
    const [size, setSize] = useState([window.innerHeight, window.innerWidth]);
    useEffect(() => {
        let timeoutId = null;
        const resizeListener = () => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => setSize([window.document.body.offsetHeight, window.document.body.offsetWidth]), 150);
        };
        window.addEventListener("resize", resizeListener);
        return () => {
            window.removeEventListener("resize", resizeListener)
        };
    })
    return size;
}

I'd like to make it so that the initial value of size uses the window.document.body.offsetHeight, however I can't determine why my function doesn't seem to accept anything but window.innerHeight initially. The strange thing is that as soon as I resize it, the second part of the function works and the window.document.body.offsetHeight is returned.

CodePudding user response:

Why don't you call the resize event manually inside the useEffect (which runs after the render, so the document layout should have been set) ?

function useWindowSize() {
    const [size, setSize] = useState([window.innerHeight, window.innerWidth]);
    useEffect(() => {
        let timeoutId = null;
        const resizeListener = () => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => setSize([window.document.body.offsetHeight, window.document.body.offsetWidth]), 150);
        };
        window.addEventListener("resize", resizeListener);
        resizeListener(); // manually call the resize handler once to set it up 
        return () => {
            window.removeEventListener("resize", resizeListener)
        };
    }, []) // add an empty dependency array so that it only re-runs on unmount
    return size;
}

CodePudding user response:

The problem is that your useWindowSize hook is run before the client has actually rendered the page. The simplest solution is to call resizeListener once in the useEffect function, since useEffect runs after the page has been rendered.

function getWindowSize() {
    return [window.document.body.offsetHeight, window.document.body.offsetWidth];
}

function useWindowSize() {
    const [size, setSize] = useState(getWindowSize());
    useEffect(() => {
        let timeoutId = null;
        const resizeListener = () => {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => setSize(getWindowSize()), 150);
        };

        resizeListener(); // this will correctly set the size after the page has been rendered.

        window.addEventListener("resize", resizeListener);
        return () => {
            window.removeEventListener("resize", resizeListener)
        };
    })
    return size;
}

This will set the width and height initially to 0, and then to the correct value the next frame.

  • Related