Reactアニメーションライブラリ Framer MotionのHooksを試してみた

2022.05.27

こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。

今回は、Framer Motionで提供されているhooksを使用してみたいと思います。

Framer

Framerとは、コードベースのUIデザインツールになります。Framer側、React側それぞれでデザインをインポートし、取り込めるのが特徴です。

以下の記事がわかりやすいです。

Framer Motion

Framer Motionは、Framerで作成したコンポーネントに対応したReactアニメーションライブラリです。

基本的な動作については、こちらの記事で紹介されています。

Framer Motionにはコンポーネントに渡すprops以外にも、面白いhooksを提供しています。

今回は以下の3つを試してみました。

  • useCycle
  • useReducedMotion
  • useDragControls

使用準備

Framer Motionをインストールします

yarn add framer-motion
// または
npm install framer-motion

useCycle

メソッドが発火するたびに、引数に渡した値を循環させます。 以下の例では、cycleX()が呼び出されるたびに値が0,50,100,150と変化していき、0に戻ります。

import { motion, useCycle } from "framer-motion";

const Sample = () => {
  const [x, cycleX] = useCycle(0, 50, 100, 150);

  return (
    <motion.div
      style={{ width: "200px", height: "200px", background: "skyblue" }}
      animate={{ x: x }}
      onClick={() => cycleX()}
    />
  );
};

export default Sample;

動作確認

useReducedMotion

アニメーションによる影響を抑えたい場合に使用し、「動きを減らす」設定を行います。アニメーションにより、目眩などを起こすユーザーに対応するhooksです。

import { motion, useReducedMotion } from "framer-motion";
import { FC, useState } from "react";

const Box: FC<{ isOpen: boolean }> = ({ isOpen }) => {
  const shouldReduceMotion = useReducedMotion();
  const closedX = shouldReduceMotion ? 0 : "-100%";

  return (
    <>
      <motion.div
        style={{ width: "200px", height: "200px", background: "skyblue" }}
        animate={{
          opacity: isOpen ? 1 : 0,
          x: isOpen ? 0 : closedX,
        }}
      />
    </>
  );
};

const Sample = () => {
  const [isOpen, setIsOpen] = useState(true);

  return (
    <>
      <Box isOpen={isOpen} />
      <button onClick={() => setIsOpen(!isOpen)}>
        {isOpen ? "close" : "open"}
      </button>
    </>
  );
};

export default Sample;

falseの場合

trueの場合

useDragControls

ポインターイベントの実装を可能にします。useDragControls()を使用し、これをドラッグ可能なコンポーネントに渡すことで使用できます。同じくFramer Motionのstart()を使用し、カーソルの移動に対して、メソッドが発火されるよう指定します。

import { motion, useDragControls } from "framer-motion";
import { MouseEvent } from "react";

const Sample = () => {
  const dragControls = useDragControls();

  const startDrag = (event: MouseEvent) => {
    dragControls.start(event, { snapToCursor: true });
  };

  return (
    <>
      <div
        style={{ width: "100%", height: "200px"}}
        onPointerDown={startDrag}
      />
      <motion.div
        style={{ width: "200px", height: "200px", background: "skyblue" }}
        drag="x"
        dragControls={dragControls}
      />
    </>
  );
};

export default Sample;

まとめ

今回は、Framer Motionのhooksを使用して、アニメーションを実装することができました。 Framer Motionには他にも面白い機能がありそうなので、今後も試してみたいと思います。

ではまた。