React.js - How to check if the div is at the bottom of the screen (dynamically)

Viewed 34

Is there any way to check if the div is at the bottom of the another div (acting as a parent, or container).

What I tried

So basically I made demo where there are child elements (items, setItems) in the div that can be added and deleted and also you can change the height of them by clicking on the divs (important here). Also there is another div, which is not in the items state, where I want to change the title of that item, if it is at the bottom of the his parent div (also items have the same parent as this div has).

Problem with my solution

I have tried something where I am looking at the getBoundingClientRect() of the parent container and this "blue" div, lets call it like that, and it will work fine, ONLY IF the items have the same height, but soon as a delete the one item and change the height of it by clicking on the div, it will not work. It will show that it is on the bottom of the screen (the title will be true) but in reality it is not.

My code

App.js - only for demo purposes

import "./styles.css";
import { useState, useEffect, useRef } from "react";

export default function App() {
  const arrayItems = [
    {
      id: 1,
      name: "test",
      resized: false
    },
    {
      id: 2,
      name: "test1",
      resized: false
    },
    {
      id: 3,
      name: "test2",
      resized: false
    }
  ];
  const [items, setItems] = useState(arrayItems);
  const [title, setTitle] = useState(false);
  const parentRef = useRef(null);
  const itemsRef = useRef(null);

  useEffect(() => {
    if (
      parentRef?.current.getBoundingClientRect().bottom -
        itemsRef?.current.getBoundingClientRect().height <=
      itemsRef?.current.getBoundingClientRect().top
    ) {
      setTitle(true);
    } else {
      setTitle(false);
    }
  }, [parentRef, items]);

  const handleClick = () => {
    const maxValue = Math.max(...items.map((item) => item.id)) + 1;
    setItems((prev) => [
      ...prev,
      { id: maxValue, name: "testValue", resized: false }
    ]);
  };

  const handleDelete = () => {
    setItems((prev) => prev.slice(0, prev.length - 1));
  };

  const handleResize = (item) => {
    setItems((prev) =>
      prev.map((itemOld) => {
        if (itemOld.id === item.id) {
          return itemOld.resized === true
            ? { ...itemOld, resized: false }
            : { ...itemOld, resized: true };
        } else {
          return itemOld;
        }
      })
    );
  };

  console.log(items);

  return (
    <div className="App">
      <button onClick={handleClick}>Add new</button>
      <button onClick={handleDelete}>Delete last</button>
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <div ref={parentRef} className="container">
        {items?.map((item) => {
          return (
            <div
              onClick={() => handleResize(item)}
              style={{ height: item.resized ? "70px" : "20px" }}
              key={item.id}
              className="container-item"
            >
              <p>{item.name}</p>
            </div>
          );
        })}
        <div ref={itemsRef} id="title-div">
          {title ? "At the bottom" : "Not at the bottom"}
        </div>
      </div>
    </div>
  );
}

styles.css

.App {
  font-family: sans-serif;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  margin-top: 1rem;
}

* {
  margin: 0;
  padding: 0;
}

.container {
  width: 600px;
  height: 300px;
  background-color: gray;
  display: flex;
  flex-direction: column;
}

.container-item {
  width: 100%;
  background-color: hotpink;
}
#title-div {
  width: 100%;
  padding: 1rem;  
  background-color: blue;
  color: white;
}

What I want to make

As the title suggest I want to see if the div is at the bottom of the container/parent div. That is it, and other items in that parent div, cannot interfere with this div, in sense that adding, resizing, deleting those items, will not suddenly change the position of the div that I want to analyse (to see if it is at the bottom of the screen)

1 Answers

I have come up with my own solution and it works always. I just have to deduct the "top" from parentsRef and "top" from the itemsRef, and add to that the clientHeight of the itemsRef. This way it will always be at the bottom of the container, doesnt matter if I delete the items, resize them etc.

The code

  useEffect(() => {
    if (
      parentRef?.current.clientHeight <=
      itemsRef?.current.getBoundingClientRect().top -
        parentRef?.current.getBoundingClientRect().top +
        itemsRef?.current.clientHeight
    ) {
      setTitle(true);
    } else {
      setTitle(false);
    }
  }, [parentRef, items, itemsRef]);
Related