4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Reactで一番下までスクロール

Last updated at Posted at 2020-05-20

ちょっとしたことですが、以下のようなスクロールでちょっと詰まったので覚書程度に。。:writing_hand:
ダウンロード (1).gif

やりたいこと

コンポーネント内でボタンを押す

アコーディオンが開く

指定位置までスクロールする

スクロールなかったら下にちょろっと出てくるだけなのであんまりよろしく無いかな〜と思いやってみました。

アコーディオン開くまで

App.js

const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  const changeIsOpen = () => {
    setIsOpen(!isOpen);
  };

  return (
    <div className="App">
      <div className="wrapper">
        <button onClick={changeIsOpen}>Click Me!</button>
        <ul id="target" className={isOpen ? "ul open" : "ul close"}>
          <li>list1</li>
          <li>list2</li>
        </ul>
      </div>
    </div>
  );
};

export default App;

(styled-component使ってましたがとりあえず参考に…)

style.css
.ul {
  margin: auto;
  list-style: none;
  max-height: 0;
  overflow: hidden;
}

.open {
  max-height: 500px;
  transition: max-height 0.5s;
}

.close {
  max-height: 0;
  transition: max-height 0.5s;
}

試したこと1


const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  const changeIsOpen = () => {
    setIsOpen(!isOpen);
    const target = document.getElementById("target");
    target.scrollIntoView({ behavior: "smooth", block: "end" });
  };

  return (
    <div className="App">
      <div className="wrapper">
        <button onClick={changeIsOpen}>Click Me!</button>
        <ul id="target" className={isOpen ? "ul open" : "ul close"}>
          <li>list1</li>
          <li>list2</li>
        </ul>
      </div>
    </div>
  );
};

export default App;

onClickの時に一緒に処理しようと思ったけどisOpenが変わる前に処理が走ってしまうので上手くいかなかった。

試したこと2

そりゃそうか…と思いながらuseEffectを使いましたがまだちゃんと動かない…


const App = () => {
  const [isOpen, setIsOpen] = useState(false);

  const ScrollBottom = target => {
    if (target) {
      target.scrollIntoView({ behavior: "smooth", block: "end" });
    }
  };

  const changeIsOpen = () => {
    setIsOpen(!isOpen);
  };

  useEffect(() => {
     const target = document.getElementById("target");
     if (target) {
         ScrollBottom(target)
     }
   }, [isOpen]);

  return (
    <div className="App">
      <div className="wrapper">
        <button onClick={changeIsOpen}>Click Me!</button>
        <ul id="target" className={isOpen ? "ul open" : "ul close"}>
          <li>list1</li>
          <li>list2</li>
        </ul>
      </div>
    </div>
  );
};

export default App;

原因はCSSのtransitionでした。
transitionで0.5s指定しているので、アコーディオンが開く前にjs動いていたようです。

解決

アコーディオンの要素にaddEventListenertransitionendをとってスクロールを動かしました。あとイベントが残っていくのでreturnでremoveEventListenerも。


  useEffect(() => {
    const target = document.getElementById("target");
    if (target) {
      target.addEventListener("transitionend", () => {
        ScrollBottom(target);
      });
      return () => {
        target.removeEventListener("transitionend", () => {
          ScrollBottom(target);
        });
      };
    }
  }, [isOpen]);

サンプル
https://codesandbox.io/s/transition-l0o2z?file=/src/App.js

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?