💦

Next.js + Framer Motion でページ遷移アニメーションを実装したいが、「exit」が走らない

2022/04/23に公開

記事のコンセプト

この記事は「Framer Motionでページ遷移のアニメーションを作りたいが、exitの処理が動かない!」とお困りの方に向けた記事です。

スタックオーバーフローでも同じ悩みの質問がありましたが、解決している記事は見かけませんでした。

同じ悩みを持った同士の手助けができるよう、備忘録として残します。

結論

NEXT以外のLinkコンポーネントを使っているから。

かもしれません。

開発環境

  • Next.js
  • TypeScript
  • MUI
  • Framer Motion

経緯

Next.jsでページ遷移時、フェードアウト→フェードインするアニメーションを「Framer Motion」で作りたいなーと思った。
そこでこちらの記事を参考にさせて頂きながら実装してみた。

// _app.tsx
import { AnimatePresence } from "framer-motion";

const MyApp = ({ Component, pageProps, router }: AppProps) => (
    <AnimatePresence exitBeforeEnter>
        <Component key={router.asPath} {...pageProps} />
    </AnimatePresence>
);

export default MyApp;
// レイアウト用のファイル
export default function Layout(props: Props) {
    return (
        <ThemeProvider theme={theme}>
            <CssBaseline />
            <Header />
	    // ヘッダー直下に配置
            <motion.div
                    initial={{ opacity: 0, y: 10 }} // 初期状態
                    animate={{ opacity: 1, y: 0 }} // マウント時
                    exit={{ opacity: 0, y: 10 }} // アンマウント時
                    transition={{
                    duration: 0.5,
                    }}
            >
                <Container>
                    {props.children}
                </Container>
            </motion.div>
        </ThemeProvider>
    );
}

これでページ遷移するたびに、0.5秒掛けて下にフワッとフェードアウトして、フワッとフェードインするはず。

わくわく。

しかし、そこでハマった。

「exit」が動作しない。

ページ遷移した際「initial」「animate」は意図した通り作動し、下からフワッと表示される。

だが、「exit」のアニメーションが作動しているようには見えなかった。

つまり、パッと消えてフワッとなるのだ。

なんでだ。。

記述場所を変えてみたり、公式ページや英語の記事を読んだりしながらいろいろ試行錯誤。

そして約1時間後、何とか原因を突き止められた。

原因考察

私の場合

MUIのLinkコンポーネントを使っていたから。

でした。

- import { Link } from "@mui/material";
+ import Link from "next/link";

偶然、Next.jsのリンクコンポーネントで試してみたら、
思った通りのフワッと消えてフワッと現れるアニメーションが実現しました。

奇跡。

MUIのLinkコンポーネントはアイコンとか設定し易いという理由で使っていましたが、どうやら「Framer Motion」と相性が悪かったらしいです。

これがexitが走らない全ての原因なのかはわかりませんが、とにかく私のアニメーションは動きました。

あとがき

今後からはNext.jsのリンクコンポーネントを使っていくことにします。😅

また、他にも同じ名前のコンポーネントが他にもあった場合、Next.jsで提供されているものを優先して使って行こうと思います。

意図しない挙動をした時はぜひ、コンポーネントの提供元を変えることを試してみてください。

Discussion