React how to dynamically set div height to follow suit of full window height including scroll
Asked Answered
O

4

10

I'm making a react redux app.

My view gets bigger as I add elements (or smaller as I remove them) but I can't get my background to follow suit correctly.

I've tried using scrollHeight to determine the size it should have :

https://i.imgur.com/HGHJgub.gifv

Here is my code :

constructor(props) {
    super(props);
    this.state = {
        heightSet: 0,
    };
    this.updateDimensions = this.updateDimensions.bind(this);
}

componentDidMount() {
    this.updateDimensions();
    window.addEventListener('resize', this.updateDimensions);
}

componentWillUnmount() {
    window.removeEventListener('resize', this.updateDimensions);
}

updateDimensions() {
    this.setState({ heightSet: document.body.scrollHeight });
    console.log(document.body.scrollHeight);
}

render() {
    const divStyle = {
        height: this.state.heightSet + 'px',
    };
    return (
        <div style={divStyle}>
        </div>
    )
}

but All of this is clearly to be ditched. I'm not taking the right approach. It also touches on another issue of my app : It knows to add height to the view but not to remove it. Anybody know why it has this behavior and how to remedy it?

UPDATE :

CLARIFICATION the real issue is that this solution doesn't have any update on the var when I click "add component" and my scroll height increases. all in all the above solution is utter garbage. I like this idea : Set color for extra page parts visible during rubber band scroll (yeah it's a hack but that's fine by me)

from Shishir Arora and tksb

but it seems it does not work on modern browsers (at least not Chrome and latest Chrome is target N°1 for my app).

Obey answered 29/9, 2017 at 9:56 Comment(3)
#30640946Buckingham
weird. sounds promising but ended up not working. the 50% above and 50% below count as part of the page not outside of the view even with the simplest of layouts.Obey
any new ideas ???Obey
O
0

So as it turns out you CAN do this with css only and the trick is deceptively easy:

in your navbar component add this :

render() {
        return (
            <Navbar>
                <div className="top-nav-white" />

                ...content

            </Navbar>
        );
    }

and in css :

.top-nav-white{
  background-color: white; // (or the color you want to be overflowing)
  height: 100px;
  width: 100%;
  position: absolute;
  top: -100px;
}

this way you can leave the backround color on html or body :

html{
}
body{
  height: 100vh;
  margin: 0;
  padding: 0;
  background-color: $fond;
}

and therefore your overflow color on the top of the page and the bottom of the page will be different as desired.

Obey answered 12/10, 2017 at 10:33 Comment(0)
I
4
import React, { useRef, useLayoutEffect, useState } from "react";

const Home = props => {
  const targetRef = useRef();
  const [dimensions, setDimensions] = useState({ width: 0, height: 0 });
  const [initVal, setInitVal] = useState(0);
  const [height, setHeight] = useState({});

  useLayoutEffect(() => {
    if (targetRef.current) {
      setDimensions({
        width: targetRef.current.offsetWidth,
        height: targetRef.current.offsetHeight
      });
      setHeight({
        height: targetRef.current.offsetHeight + "px",
        border: "1px solid red"
      })
    }

  }, []);

  const hanleInput = (e) => {
    setInitVal(e.target.value);
  }

  const increaseHeight = () => {
    let totalHeight = Number(dimensions.height) + Number(initVal);
    setDimensions({
      width: targetRef.current.offsetWidth,
      height: totalHeight
    });
    setHeight({
      height: totalHeight + "px",
      border: "1px solid red"
    })
    setInitVal(0);
  }

  return (
    <div ref={targetRef} style={height} >
      <p>{dimensions.width}</p>
      <p>{dimensions.height}</p>
      <input type="number" value={initVal} onChange={hanleInput} />
      <button onClick={increaseHeight}>increaseHeight</button>
    </div>
  );
};

export default Home;
Interbedded answered 21/2, 2020 at 7:56 Comment(0)
M
3

I reproduced the scenario and I got to this. Hope it helps.

Why is it always growing?

In my case, document.body.scrollHeight is returning the height of the body with its margin (for some reason), so every time the component height is set it keeps being smaller than the body's scrollHeight and given that the body grows with its children, with the resize, the component just keeps growing.

For Example:

 componentDidMount : 
   bodyHeight = 90 + 10 (a margin)
   scrollHeight = 100
   componentHeight = 100

   newBodyHeight = 100 + 10 

 Resize:
   bodyHeight = 100 + 10 
   scrollHeight = 110
   componentHeight = 110

   newBodyHeight = 110 + 10 , and so on.

How to remedy it?

You could subtract the margin of the body from the scrollHeight or calculate the height from the component's children's height.

I just changed this:

updateDimensions() {
  const margin = 16; // In my case was marginTop: 8px and marginBottom: 8px
  const heightSet = document.body.scrollHeight - margin;
  this.setState({ heightSet });
}
Manila answered 6/10, 2017 at 2:56 Comment(4)
i already had that and it doesn't correspond to the scroll height of the page. it corresponds to a fixed height that doesn't update as the content gets bigger.Obey
have you tried having dynamic components in your page and seeing the effect on the variable as you click on the "add" button and the page scroll length increases? when the page scroll length increases for me the variable doesn't increase.Obey
No, the variable does not increase because that does not trigger the resize. You can update the wrapper's height with its children's height. Something like thisManila
a great number of things are broken in the linked demo including : removing, scrolling once elements are added, adding and also most or none of the linked code can be applied to react :/ for example "offsetHeigh" does not exist in react.Obey
O
0

So as it turns out you CAN do this with css only and the trick is deceptively easy:

in your navbar component add this :

render() {
        return (
            <Navbar>
                <div className="top-nav-white" />

                ...content

            </Navbar>
        );
    }

and in css :

.top-nav-white{
  background-color: white; // (or the color you want to be overflowing)
  height: 100px;
  width: 100%;
  position: absolute;
  top: -100px;
}

this way you can leave the backround color on html or body :

html{
}
body{
  height: 100vh;
  margin: 0;
  padding: 0;
  background-color: $fond;
}

and therefore your overflow color on the top of the page and the bottom of the page will be different as desired.

Obey answered 12/10, 2017 at 10:33 Comment(0)
A
0

hook onto the scroll event and not to the resize event

componentDidMount() {
    this.updateDimensions();
    window.addEventListener('scroll', this.updateDimensions);
}

componentWillUnmount() {
    window.removeEventListener('scroll', this.updateDimensions);
}

updateDimensions = () => {
    this.setState({heightSet: document.body.scrollHeight});
    console.log(document.body.scrollHeight);
}
Aftmost answered 13/1, 2019 at 15:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.