Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Track if a component is on or off screen

I have a component A that renders once the application loads.

I am looking to render another component B the moment component A leaves
the screen. This happens when the user scrolls component A off screen.

And also when user scrolls component A back into the screen, component B should
disappear.

Looking for guidance on how I could track whether component A is on the screen or off screen in React.
Please advice.

Idea is below. Looking for a way to listen if component A is on screen or not and setShowB(false) or setShowB(true) accordingly.

import React, { useState } from 'react';

const AComponent = () => {
  const [showB, setShowB] = useState(false); // I do want this to be a boolean
  const setVisibility = (showB) => showB ? 'visible' : 'hidden'

  return (
    <div>

      <div id='A' style={{ visibility: setVisibility(showB)}}>
        I am component A
      </div>

      <div id='B'>
        I am component B
      </div>

    </div>
  );
};

export default AComponent;

Note: Not looking to use any external libraries.

On page load only Component A shows.

enter image description here

===================================================================

when component A is scrolled off screen component B shows up.

enter image description here

like image 401
Fllappy Avatar asked Sep 02 '25 16:09

Fllappy


1 Answers

You can try this solution and build on top of this as per your requirement. You need to use useEffect() Hook to put all your scrolling code and manage state accordingly. useEffect() is used to manage all the sideEffects and for user scrolling useEffect() is the best place to write our Logic.

CODESANDBOX: https://codesandbox.io/s/help-friend-stackoverflow-x15jf?file=/src/App.js

TOTAL COMPONENTS USED:

App.js

import "./styles.css";
import ComponentA from "./components/ComponentA";
import ComponentB from "./components/ComponentB";
import OtherComponent from "./components/OtherComponent";
import { useState, useEffect } from "react";

export default function App() {
  const [isAOpen, setIsAOpen] = useState(true);

  useEffect(() => {
    window.addEventListener("scroll", () => {
      // let componentHeight = document.querySelector(".compA").clientHeight;
      let scrolled = window.scrollY;

      console.log(scrolled);

      if (scrolled >= 530) {
        setIsAOpen(false);
      } else if (scrolled <= 10) {
        setIsAOpen(true);
      }
    });

    return () => {
      window.removeEventListener("scroll", () => {
        // let componentHeight = document.querySelector(".compA").clientHeight;
        let scrolled = window.scrollY;

        console.log(scrolled);

        if (scrolled >= 530) {
          setIsAOpen(false);
        } else if (scrolled < 0) {
          setIsAOpen(true);
        }
      });
    };
  }, [isAOpen]);

  return (
    <main>
      {isAOpen ? <ComponentA /> : <ComponentB />}
      <OtherComponent />
    </main>
  );
}

ComponentA.js

import React, { useState, useEffect } from "react";

const ComponentA = () => {
  return (
    <main className="compA">
      <h1>COMPONENT-AYE</h1>
    </main>
  );
};

export default ComponentA;

ComponentB.js

import React, { useEffect } from "react";

const ComponentB = () => {
  useEffect(() => {
    console.log("component-B showing up");
  });
  return (
    <main className="compB">
      <h1>COMPONENT-Bee</h1>
    </main>
  );
};

export default ComponentB;

OtherComponent.js

import React, { useState, useEffect } from "react";

const OtherComponent = () => {
  return (
    <main className="compOther">
      <h1>OTHER COMPONENT AND DATA</h1>
    </main>
  );
};

export default OtherComponent;

For simplicity I have kept all the styles in styles.css file

style.css

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

.App {
  font-family: sans-serif;
  text-align: center;
}

.compA,
.compB {
  height: 500px;
  display: flex;
  justify-content: center;
  align-items: center;
}

.compA {
  background: green;
}
.compB {
  background: rgb(238, 94, 58);
  margin-top: 500px;
}

.compOther {
  height: 130vh;
  background: rgb(58, 241, 241);
}

Note: you need to make some basic changes while scrolling back to top (perhaps remove the margin-top on ComponentB. That's an exercise for you. Cheers !!!)

like image 149
Imran Rafiq Rather Avatar answered Sep 04 '25 06:09

Imran Rafiq Rather