4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

AnimatePresenceに慣れる[framer-motion]

Last updated at Posted at 2022-12-24

背景

  • framer-motionを使うことで、React Componentのマウント・アンマウント時にアニメーションを定義することができる。
  • このうち、アンマウントについては、 対象のコンポーネントを AnimatePresence コンポーネントでラップする必要があるが、少しクセがあるので、ここで説明する。

基本的な利用方法

  • ロードが完了したら(loaded=true)、Spinnerをフェードアウトして、Contentコンポーネントをフェードインさせる例。
  • 必ず、AnimatePresence の直下のコンポーネントにkeyを付ける必要がある。
  • Spinnerのフェードアウトを待ってからContentをフェードインさせたいので exitBeforeEnter を付ける。
<AnimatePresence exitBeforeEnter>
  {loaded && (
    <motion.div key="content" init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0}}>
      <Content  />
    </motion.div>
  )}
  {!loaded && (
    <motion.div key="spinner" init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0}}>
      <Spinner />
    </motion.div>
  )}
</AnimatePresence>

その他できること

  • 上記は単純なフェードイン・フェードアウトだが、直下のコンポーネントに key をつけることを守っていれば、アニメーションは、子孫のコンポーネントで定義することもできる。
  • 直下のコンポーネントは、自作のコンポーネントでもOK。
<AnimatePresence exitBeforeEnter>
  {loaded && (
    <Content key="content" />
  )}
  {!loaded && (
    <Spinner key="spinner" />
  )}
</AnimatePresence>

// Spinner.tsx
<div>
  <motion.div init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0, x: -1}}>
    loadが終わったら、左に消える
  </motion.div>
  <motion.div init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0, x: 1}}>
    loadが終わったら、右に消える
  </motion.div>
</div>

できないこと

  • AnimatePresenceをネストさせると、子のAnimatePresence以下にあるexitアニメーションは効かなくなってしまう。
  • 下記の例の場合、 <div key="content"> のアンマウント時に、 <motion.div key="content1"> の アニメーション (exit={{opacity: 0, x: -1}})は効かなくなる。
  • https://github.com/framer/motion/issues/746
<AnimatePresence exitBeforeEnter>
  {loaded && (
    <div key="content">{/* ここのアンマウント時に */}
      <AnimatePresence exitBeforeEnter>
        {tab1 && (
          <motion.div key="content1" init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0, x: -1}}>
            <Content1  />{/* ここのアニメーションは効かない */}
          </motion.div>
        )}
        {tab2 && (
          <motion.div key="content2" init={{opacity: 0}} animate={{opacity: 1}} exit={{opacity: 0, x: -1}}>
            <Content2  />
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  )}
  {!loaded && (
    <div key="spinner">
      <Spinner />
    </div>
  )}
</AnimatePresence>
4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?