Search code examples
javascriptreactjsscrollview

React ScrollIntoView Does not work when scrolled to top


The Problem :- The scrollIntoView is working fine but, it fails for this scenario when suppose I click on John Doe it scrolls to that section but now when I scroll to top and select again John Doe then it does not get scrolled to that particular section Why is this happening ? Note :- This happens for all the buttons not just for John Doe

In the useEffect Dependency array I have added the selectedAdvisor state variable so that whenever it changes then it should scrollIntoView of that section based on the id

Expected Output :- scrollIntoView should work properly even if I scroll to top and then select the element that was already selected example John Doe

Below is my code :-

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

function AdvisorCard() {
  return <div className="advisorCard"></div>;
}
export const NewFilterAdvisor = () => {
  const [selectedAdvisor, setSelectedAdvisor] = useState("Tony Stark");

  useEffect(() => {
    let ele = document.getElementById(`${selectedAdvisor}`);
    if (ele) {
      ele.scrollIntoView({
        behavior: "smooth",
        block: "center",
      });
    }
  }, [selectedAdvisor]);

  return (
    <div className="newFilterAdvisorContainer">
      <div className="advisorsBtnContainer">
        <button
          onClick={() => setSelectedAdvisor("Tony Stark")}
          className="advisorBtn"
        >
          Tony Stark
        </button>
        <button
          onClick={() => setSelectedAdvisor("Steve Rogers")}
          className="advisorBtn"
        >
          Steve Rogers
        </button>
        <button
          onClick={() => setSelectedAdvisor("Bruce Banner")}
          className="advisorBtn"
        >
          Bruce Banner
        </button>
        <button
          onClick={() => setSelectedAdvisor("Thor")}
          className="advisorBtn"
        >
          Thor
        </button>
        <button
          onClick={() => setSelectedAdvisor("John Doe")}
          className="advisorBtn"
        >
          John Doe
        </button>
      </div>

      <div id="Tony Stark" className="advisorSection">
        <h1 className="advisorCardContainerHeading">Tony's Advisors</h1>
        <div className="advisorCardContainer">
          <AdvisorCard />
          <AdvisorCard />
          <AdvisorCard />
        </div>
      </div>

      <div id="Steve Rogers" className="advisorSection">
        <h1 className="advisorCardContainerHeading">Steve's Advisors</h1>
        <div className="advisorCardContainer">
          <AdvisorCard />
          <AdvisorCard />
          <AdvisorCard />
        </div>
      </div>

      <div id="Bruce Banner" className="advisorSection">
        <h1 className="advisorCardContainerHeading">Bruce's Advisors</h1>
        <div className="advisorCardContainer">
          <AdvisorCard />
          <AdvisorCard />
          <AdvisorCard />
        </div>
      </div>

      <div id="Thor" className="advisorSection">
        <h1 className="advisorCardContainerHeading">Thor's Advisors</h1>
        <div className="advisorCardContainer">
          <AdvisorCard />
          <AdvisorCard />
          <AdvisorCard />
        </div>
      </div>

      <div id="John Doe" className="advisorSection">
        <h1 className="advisorCardContainerHeading">John's Advisors</h1>
        <div className="advisorCardContainer">
          <AdvisorCard />
          <AdvisorCard />
          <AdvisorCard />
        </div>
      </div>
    </div>
  );
};

CodeSandBoxLink :- https://codesandbox.io/s/keen-darkness-g42qjw?file=/src/App.js:1443-1470

Where am I going wrong ? please help


Solution

  • The issues is that if you select same item after you scroll up, you'd update the state to the same value and the useEffect won't run. Actually you don't even need an internal state. This would do just fine:

    import React from "react";
    import "./styles.css";
    function AdvisorCard() {
      return <div className="advisorCard"></div>;
    }
    export default function App() {
      const handleSelectItem = (id) => {
        let ele = document.getElementById(`${id}`);
        if (ele) {
          ele.scrollIntoView({
            behavior: "smooth",
            block: "center"
          });
        }
      };
    
      return (
        <div className="newFilterAdvisorContainer">
          <div className="advisorsBtnContainer">
            <button
              onClick={() => handleSelectItem("Tony Stark")}
              className="advisorBtn"
            >
              Tony Stark
            </button>
            <button
              onClick={() => handleSelectItem("Steve Rogers")}
              className="advisorBtn"
            >
              Steve Rogers
            </button>
            <button
              onClick={() => handleSelectItem("Bruce Banner")}
              className="advisorBtn"
            >
              Bruce Banner
            </button>
            <button
              onClick={() => handleSelectItem("Thor")}
              className="advisorBtn"
            >
              Thor
            </button>
            <button
              onClick={() => handleSelectItem("John Doe")}
              className="advisorBtn"
            >
              John Doe
            </button>
          </div>
    
          <div id="Tony Stark" className="advisorSection">
            <h1 className="advisorCardContainerHeading">Tony's Advisors</h1>
            <div className="advisorCardContainer">
              <AdvisorCard />
              <AdvisorCard />
              <AdvisorCard />
            </div>
          </div>
    
          <div id="Steve Rogers" className="advisorSection">
            <h1 className="advisorCardContainerHeading">Steve's Advisors</h1>
            <div className="advisorCardContainer">
              <AdvisorCard />
              <AdvisorCard />
              <AdvisorCard />
            </div>
          </div>
    
          <div id="Bruce Banner" className="advisorSection">
            <h1 className="advisorCardContainerHeading">Bruce's Advisors</h1>
            <div className="advisorCardContainer">
              <AdvisorCard />
              <AdvisorCard />
              <AdvisorCard />
            </div>
          </div>
    
          <div id="Thor" className="advisorSection">
            <h1 className="advisorCardContainerHeading">Thor's Advisors</h1>
            <div className="advisorCardContainer">
              <AdvisorCard />
              <AdvisorCard />
              <AdvisorCard />
            </div>
          </div>
    
          <div id="John Doe" className="advisorSection">
            <h1 className="advisorCardContainerHeading">John's Advisors</h1>
            <div className="advisorCardContainer">
              <AdvisorCard />
              <AdvisorCard />
              <AdvisorCard />
            </div>
          </div>
        </div>
      );
    }