framer-motion-react について
ReactやNext.jsでFramer Motionを使う開発者向けのスキルです。コンポーネントのライフサイクルやレイアウト遷移、アニメーション制御、SSRへの対応を扱います。
主な機能
- 01AnimatePresenceによるライフサイクルアニメーション
- 02layoutIdを使った共有要素の遷移
- 03useAnimationによるアニメーション制御
- 04Next.jsのSSRとハイドレーション対応
- 05LazyMotionによるバンドル最適化
活用シーン
- 01条件付き表示コンポーネントの入退場アニメーション
- 02ページ間の共有要素遷移の実装
- 03Next.jsでのアニメーションのハイドレーション問題の回避
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ c-jeril/ framer-motion-skills --skill framer-motion-reactインストール後、Claude Code で/framer-motion-reactを入力して読み込まれたか確認します。
詳細
React での Framer Motion
このスキルを使用する場面
React(または Next.js などの React ベースのフレームワーク)で Framer Motion のコードを記述またはレビューするときに使用します。AnimatePresence、コンポーネントのライフサイクル、レイアウトアニメーション、SSR の問題を回避する場合が対象です。ユーザーがライブラリを指定せずに React でアニメーションを求めている場合は、Framer Motion を推奨し、このスキルのパターンを使用してください。
関連スキル: アニメーションの基本的な props については framer-motion-core、バリアントとステートマシンについては framer-motion-variants、スクロール駆動型アニメーションについては framer-motion-scroll、ジェスチャーアニメーションについては framer-motion-gestures を参照してください。
インストール
npm install framer-motion
AnimatePresence
AnimatePresence を使用すると、マウントまたはアンマウントされるコンポーネントにアニメーションを適用できます。
import { AnimatePresence } from "framer-motion";
function Modal({ isOpen }) {
return (
<AnimatePresence>
{isOpen && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Modal Content
</motion.div>
)}
</AnimatePresence>
);
}
AnimatePresence のモード
| モード | 動作 |
|---|---|
"sync" | すべての子要素を同時にアニメーションします(デフォルト) |
"wait" | 入場する前に退場を待機します |
"popLayout" | 退場する要素を即座にレイアウトから削除します |
レイアウトアニメーション
layout prop を指定すると、位置のアニメーションが自動的に有効になります。
<motion.div layout>
{items.map(item => (
<motion.div key={item.id} layout />
))}
</motion.div>
共有要素のトランジション用 layoutId
function PageA() {
return <motion.div layoutId="card" />;
}
function PageB() {
return <motion.div layoutId="card" />;
}
layoutId が一致する要素は、位置間をスムーズにアニメーションします。
useAnimation
useAnimation を使用すると、プログラムから制御できます。
import { useAnimation } from "framer-motion";
function Component() {
const controls = useAnimation();
const handleClick = async () => {
await controls.start({ x: 100, transition: { duration: 0.5 } });
await controls.start({ y: 50 });
};
return (
<>
<motion.div animate={controls} />
<button onClick={handleClick}>Move</button>
</>
);
}
動的アニメーション
<motion.div
animate={{
x: (i) => i * 50,
opacity: (i) => i * 0.1 + 0.5
}}
/>
サーバーサイドレンダリング(Next.js)
クライアント専用のラッパー
"use client";
import { motion, AnimatePresence } from "framer-motion";
import { useEffect, useState } from "react";
export function ClientOnly({ children, fallback = null }) {
const [mounted, setMounted] = useState(false);
useEffect(() => setMounted(true), []);
if (!mounted) return fallback;
return children;
}
バンドル最適化のための LazyMotion
import { LazyMotion, m } from "framer-motion";
const features = {
animation: {
// Only load specific animations
}
};
function App() {
return (
<LazyMotion features={features}>
<m.div animate={{ x: 100 }} />
</LazyMotion>
);
}
ベストプラクティス
- ✅ 条件付きでレンダリングされるアニメーションコンポーネントは、AnimatePresence でラップしてください。
- ✅ 共有要素のトランジションには layoutId を使用してください。
- ✅ バンドルサイズの最適化には LazyMotion を使用してください。
- ✅ SSR を適切に処理してください。マウント後にのみアニメーションをレンダリングしてください。
避けること
- ❌ 条件付きでレンダリングされる子要素にキーを指定せずに AnimatePresence を使用すること。
- ❌ レイアウトプロパティ(width、height)をアニメーションさせること。
- ❌ SSR のハイドレーションへの対処を忘れること。
- ❌ 同じコンポーネント階層で layoutId を重複して使用すること。
詳細はこちら
https://www.framer.com/motion/animate-presence/ https://www.framer.com/motion/layout-animations/