0

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.

Botonian
  • 87
  • 6
  • What do you mean by `however the function won't work if I don't start with window.innerHeight.`? What's the error you receive? – Andreas Winther Moen Jan 28 '23 at 13:49
  • I mean the function works, but not how intended. Because the user must scroll, I want to have the height of the entire document. However window.innerHeight only retrieves the viewport size, which isn't what I'd like. But when I try using window.document.offsetHeight in the initial section, the function doesn't work at all. It does however work in the resize portion. – Botonian Jan 28 '23 at 13:50
  • Does [this](https://stackoverflow.com/questions/1145850/how-to-get-height-of-entire-document-with-javascript) answer your question? – Bernard Borg Jan 28 '23 at 13:58
  • @BernardBorg it still seems to be giving me the same error as with window.innerHeight – Botonian Jan 28 '23 at 14:06
  • Looking more into the issue, window.document.body.offsetHeight seems to initially return 0, which I don't understand. That it the main issue. – Botonian Jan 28 '23 at 14:09
  • offsetHeight will be 0 initially if this hook is run before the client has actually rendered the page. This makes sense, as window.document.body will be empty. It will, however, trigger a resize event when it has finished the initial render. – Andreas Winther Moen Jan 28 '23 at 14:13
  • @AndreasWintherMoen By that do you mean it will find the actual height after page has loaded properly even without someone resizing the page? It seems for me it just continually stays 0, unless I trigger the resize event, it stays at 0. – Botonian Jan 28 '23 at 14:16

2 Answers2

1

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;
}
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
0

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.