🏎️
React + Intersection Observerで作る超軽量なInViewコンポーネント(Tailwind対応)
React + Intersection Observerで作る超軽量なInViewコンポーネント(Tailwind対応)
Reactでアニメーションや表示制御によく使う「in-view検出」。今回は、Intersection Observer API を活用した超軽量なInViewコンポーネントを作成し、Tailwind CSSで簡単にスタイリングできる形にまとめます。
なぜ軽量?
-
ライブラリ不使用(
framer-motion
やreact-intersection-observer
などに頼らない) - IntersectionObserverをラップしただけのシンプルなロジック
- Tailwindのユーティリティクラスでアニメーション切り替え
そのため、JSバンドルの肥大化を防げて、汎用性の高いコンポーネントとして活用できます。
コード全体(コピペOK)
InView.tsx
import { useEffect, useRef, useState } from "react";
type Props = {
children: React.ReactNode;
threshold?: number;
once?: boolean;
className?: string;
inViewClass?: string;
};
const InView = ({
children,
threshold = 0.1,
once = true,
className = "opacity-0 translate-y-8 transition duration-700",
inViewClass = "opacity-100 translate-y-0",
}: Props) => {
const ref = useRef<HTMLDivElement>(null);
const [isIntersecting, setIsIntersecting] = useState(false);
useEffect(() => {
if (!ref.current) return;
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsIntersecting(true);
if (once) observer.unobserve(entry.target);
} else if (!once) {
setIsIntersecting(false);
}
},
{ threshold }
);
observer.observe(ref.current);
return () => observer.disconnect();
}, [threshold, once]);
return (
<div
ref={ref}
className={`${className} ${isIntersecting ? inViewClass : ""}`.trim()}
>
{children}
</div>
);
};
export default InView;
使い方
import InView from "./components/InView";
export default function Home() {
return (
<InView>
<h2 className="text-2xl font-bold">スクロールして表示される要素</h2>
</InView>
);
}
用途別パターン(Tailwind class指定)
1. 下からフェードイン(デフォルト)
<InView>
<div>fade up</div>
</InView>
2. 右からスライドイン
<InView
className="opacity-0 translate-x-8 transition duration-700"
inViewClass="opacity-100 translate-x-0"
>
<div>slide from right</div>
</InView>
3. 拡大表示(ズームイン)
<InView
className="opacity-0 scale-90 transition duration-700"
inViewClass="opacity-100 scale-100"
>
<div>zoom in</div>
</InView>
once={false}
)
4. 一度きりでなく毎回実行(<InView once={false}>
<div>in/out で毎回反応</div>
</InView>
まとめ
- Tailwindと組み合わせれば、柔軟なアニメーション制御が簡単に実現可能
- 追加ライブラリなしで軽量に実装でき、プロジェクト全体のパフォーマンスにも貢献
-
className
とinViewClass
を組み合わせて無限にパターン展開可能
プロジェクト内にコピペして即使えるので、ぜひ試してみてください。
この記事が役に立ったら、いいねやシェアしてくれたら嬉しいです!
Discussion