Reactで一番下までスクロール
ちょっとしたことですが、以下のようなスクロールでちょっと詰まったので覚書程度に。。
やりたいこと
コンポーネント内でボタンを押す
↓
アコーディオンが開く
↓
指定位置までスクロールする
スクロールなかったら下にちょろっと出てくるだけなのであんまりよろしく無いかな〜と思いやってみました。
アコーディオン開くまで
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;
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使ってましたがとりあえず参考に…)
.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;
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動いていたようです。
解決
アコーディオンの要素にaddEventListener
でtransitionend
をとってスクロールを動かしました。あとイベントが残っていくので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
Author And Source
この問題について(Reactで一番下までスクロール), 我々は、より多くの情報をここで見つけました https://qiita.com/Sotq_17/items/de97632c28c36f2e9fa1著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .