GatsbyJS のページ移動時にReact Pose でアニメーションを実装する
2019/06/17,
現在、静的サイトジェネレーターの GatsbyJS を利用してサイトを作成しています。
ページ遷移するときにフェードインフェードアウトのアニメーションを付与する方法について。
React Pose
React Pose ばアニメーションライブラリです。
日本語の参考記事
結構わかりやすくアニメーションを利用できるので、これを利用して GatsbyJS で作成したサイトにアニメーションを実装します。
GatsbyJS と React Pose を組み合わせる
マウント、アンマウントのアニメーション
React Pose には PoseGroup というコンポーネントがあります。Enter/exit transitions
コンポーネントがマウントされたときの状態、アンマウントされたときの状態を定義し、それにしたがってアニメーションさせることができます。
import posed, { PoseGroup } from 'react-pose'
const Fade = posed.div({
enter: { opacity: 1 },
exit: { opacity: 0 }
})
const Page = ({ items }) => (
<PoseGroup>
<Fade key="key" >
{/* コンテンツ */}
{/* <Main/> */}
</Fade>
</PoseGroup>
)enter にマウントされたときの状態、exitにマウントされていないときの状態を記述します。上記では opacity(透過度)を指定して、フェードインフェードアウトを実現しています。
PoseGroup は key の変化を監視して、コンポーネントがマウントされた、アンマウントされたを判別しています。
コンポーネントの中身は変化がなかったとしても、key の値を変えてやるとコンポーネントのマウント、アンマウントアニメーションが発火します。
ページ遷移時のマウント、アンマウントアニメーション
ページ遷移したときにアニメーションを発火させたい場合、key に URL を与えてやればアニメーションさせることができます。
Gatsby ではページコンポーネントやテンプレートコンポーネントでは props.location.pathname でページ URL を取得できます。
なのでページ遷移のアニメーションを実装する場合、以下のようになります。
import posed, { PoseGroup } from 'react-pose'
const Fade = posed.div({
enter: { opacity: 1 },
exit: { opacity: 0 }
})
const Page = ({ items }) => (
<PoseGroup>
<Fade key={props.location.pathname} >
{/* コンテンツ */}
{/* <Main/> */}
</Fade>
</PoseGroup>
)gatsby-browser.js の書き換え
以上を踏まえて、gatsby-browser.jsを少し書き換えます。
import React from "react"
import posed, { PoseGroup } from "react-pose"
const Transition = posed.div({
enter: { opacity: 1, delay: 300, beforeChildren: true },
exit: { opacity: 0 },
})
export const replaceComponentRenderer = ({ props, ...other }) => {
const { component } = props.pageResources
return (
<PoseGroup>
<Transition key={props.location.pathname}>
{React.createElement(component, props)}
</Transition>
</PoseGroup>
)
}replaceComponentRederer を利用して、ルートコンポーネントに PoseGroup を配置します。これでページ遷移をしたとしてもPoseGroupが常にマウントされた状態を維持します。
もう少し綺麗な実装方法がありそうな気もしますが、とりあえず、これで動作しているので良しとします。
実際の運用
このままルート要素にフェードイン、フェードアウトの処理を噛ませていたら、ページ移動のたびに一度ページが真っ白になってしまいます。
なので、私は実際には以下のようにしました
gatsby-browser.js
import React from "react"
import posed, { PoseGroup } from "react-pose"
const Transition = posed.div({})
export const replaceComponentRenderer = ({ props, ...other }) => {
const { component } = props.pageResources
return (
<PoseGroup>
<Transition key={props.location.pathname}>
{React.createElement(component, props)}
</Transition>
</PoseGroup>
)
}src/compnents/Layout.js
const Fade = posed.div({
enter: {
opacity: 1,
delay: 100,
},
exit: {
opacity: 0,
},
})
const Layout = () => (
<div>
<Header/>
<Main><Fade>{children}</Fade></Main>
<Footer/>
</div>
)各ページコンポーネントで利用している Layout コンポーネントにFadeコンポーネントを呼んでいます。
これでメインコンテンツのみをフェードさせることができます。
まとめ
以上でページ遷移のアニメーションを実装できました。
参考

