Reactでページ内のスムーススクロールおよび複数の項目から該当する各セクションへのスクロールをライブラリなしで実装する方法です。
Reactでのページ内のスムーススクロールは ref
と scrollIntoView
によりライブラリなしで実装できますが、
ランディングページのように長いページ内に複数セクションがあり、各メニュー項目をクリックした際に該当セクションまでスムーススクロールさせたい場合も同じ方法で実装できます。
ページの最後にデモページへのリンクがあります。
ref と scrollIntoView を使用したスムーススクロールの例
useRef
で ref
を宣言して、スクロールの対象となる要素に設定します。
const targetRef = useRef<HTMLDivElement | null>(null);
ターゲット要素
<div ref={targetRef} />
クリックした際の処理 handleClick
を作成して、スクロール発火のトリガーとなるクリック要素(buttonなど)の onClick
に設定します。
const handleClick = () => {
if (!targetRef.current) return;
targetRef.current.scrollIntoView({ behavior: "smooth" });
};
トリガー要素(buttonなど)
<button className="gototop" type="button" onClick={handleClick}>
Click
</button>
複数要素へのスムーススクロールの例
複数要素の場合、ターゲットに設定するrefを要素ごとに作成する必要があります。
次のように書いてしまうとセクションが多くなればなるほど記述が増えてしまうため、 map()
を使用します。
// 🙅♀️
const targetRef1 = useRef<HTMLDivElement | null>(null);
const targetRef2 = useRef<HTMLDivElement | null>(null);
const targetRef3 = useRef<HTMLDivElement | null>(null);
map()
を使用して ref
を持った配列を作成します。
const sectionNames: SectionProps[] = [
{
name: "Section 1",
},
{
name: "Section 2",
},
{
name: "Section 3",
},
];
const sections = sectionNames.map((name) => {
return {
...name,
ref: useRef<HTMLDivElement>(),
};
});
作成した sections
配列からターゲットとなるセクションととトリガー要素を作成します。
その際にセクションには ref
を付与します。
/* トリガー要素 */
<nav className="nav">
{sections.map((section) => (
<a className="navItem" key={section.name} onClick={handleClick}>
{section.name}
</a>
))}
</nav>;
/* セクション */
{
sections.map((section) => (
<section className="container" key={section.name} ref={section.ref}>
{section.name}
</section>
));
}
次に handleClick
を作成します。
1つの要素の場合と違う点は handleClick
に対象となる ref
をpropsとして渡すことで、その ref
に対して scrollIntoView()
が実行されるようにします。
const handleClick = (ref) => {
if (!ref.current) return;
ref.current.scrollIntoView({ behavior: "smooth" });
};
先ほど作成したトリガー要素の onClick
を次のように変更します。
onClick={() => handleClick(section.ref)}
複数要素に対応したページ内のスムーススクロールは完成です 🎉
参照
- useRef – React https://react.dev/reference/react/useRef (2024-03-23 参照)