React Springで始めるプチアニメーション:スタートアップ

◆ Live配信スケジュール ◆
サイオステクノロジーでは、Microsoft MVPの武井による「わかりみの深いシリーズ」など、定期的なLive配信を行っています。
⇒ 詳細スケジュールはこちらから
⇒ 見逃してしまった方はYoutubeチャンネルをご覧ください
【5/21開催】Azure OpenAI ServiceによるRAG実装ガイドを公開しました
生成AIを活用したユースケースで最も一番熱いと言われているRAGの実装ガイドを公開しました。そのガイドの紹介をおこなうイベントです!!
https://tech-lab.connpass.com/event/315703/





どもども!今回は、React Springの初期調査をまとめました。Reactで簡単にアニメーションを追加するライブラリで楽ができそうな予感です。CSSの知識があれば、簡単なアニメーションから複雑なアニメーションまで作れそうです。今回は簡単なアニメーション実装をサンプル付きで作成しています。

ご挨拶

ども!体のメンテンナンスの重要性を再認識した龍ちゃんです。ちゃんと体のメンテナンスしていますか?突然体がぶっ壊れないように、時には温泉に入ってリフレッシュしていきましょう。ボケ~っと温泉に入って脳を溶かしていきましょう。

今回は、WEBページに動きを付けるために使用した「React Spring」について基本的な動作についてまとめていきます。検証のため、それっぽいものをピックアップしてサンプルにしてみました。なので、やってみた系の記事になります。それでは本題に入っていきましょう。

React Springを使ってみる

セットアップから簡易的なサンプルまで実装していきます。以下の動画が実装したサンプルになります。Reactとの統合は、名前の通り簡単です。

実装に入っていく前に、React Springのイメージについて話していきたいと思います。React Springのイメージは、「変更前と変更後のCSSを設定するとええ感じにアニメーションが作成される」というものです。なので、CSSの知識は必須になるかと思います。CSSをしっかり書くことができる人にとっては、ライトに動きを導入することができるかと思います。

React Springのイメージ画像
変更前と変更後のCSSを記入することでよしなにやってくれます

セットアップ

それでは、セットアップと使用方法についてまとめていきます。インストール自体は、安心コマンド一発になります。

yarn add @react-spring/web

あとは、要素の部分を以下に変更することで動作します。

import { animated } from '@react-spring/web'

export default function MyComponent() {
  return (
    <animated.div
      style={
				<-- アニメーションの定義をここで書くとええ感じの動作する -->
			}
    />
  )
}

これだけでアニメーションを定義することができるので、非常に楽で便利です。環境は「Tailwind CSS」を利用しています。

にゅっと伸ばす

動画の一番端っこのサンプルになります。こちらでは、2つの値を比べる縦棒チャートをイメージしています。useSpringを使用してCSSを変更する方法について作成しています。

import { animated, useSpring } from '@react-spring/web';

// プロパティの型を定義
interface BarChartProps {
  votesA: number;
  votesB: number;
}

export const BarChart = (props: BarChartProps) => {
  const { votesA, votesB } = props;
  // 最大票数を基準に棒グラフの高さを計算
  const totalVote = votesA + votesB;
  const heightA = (votesA / totalVote) * 100;
  const heightB = (votesB / totalVote) * 100;

  console.log(heightA, heightB);

  // React Springを使用してアニメーションを適用
  const propsA = useSpring({ from: { height: '0%' }, height: `${heightA}%` });
  const propsB = useSpring({ to: { height: `${heightB}%` }, from: { height: '0%' } });

  return (
    <>
      <div className="flex h-96 w-96 flex-row items-end justify-around">
        <animated.div className={'w-10 bg-blue-400'} style={propsA} />
        <animated.div className={'w-10 bg-red-400'} style={propsB} />
      </div>
    </>
  );
};

from~toで明示されているので、わかりやすいですね。単純にheightのみを伸ばしているだけなので簡単です。もちろんpx値で表現することも可能ですが、%とpxを混合して使用することはできません。%で表現するときは、toもfromも一貫して%表記にしましょう。

線を連続で伸ばす

アニメーションを用いて、単純に線を伸ばすといった芸当も可能です。美的センスは皆無なので、単純に碁盤を書こうと思います。以下がイメージになります。

碁盤上に順次アニメーション実行

ソースは以下になります。

import { animated, useChain, useSpringRef, useTrail } from '@react-spring/web';

export const Cross = () => {
  const STROKE_WIDTH = 0.5;
  const OFFSET = STROKE_WIDTH / 2;
  const MAX_WIDTH = 100 + OFFSET * 2;
  const MAX_HEIGHT = 100 + OFFSET * 2;

  const gridApi = useSpringRef();

  const gridSprings = useTrail(16, {
    ref: gridApi,
    from: {
      x2: 0,
      y2: 0,
    },
    to: {
      x2: MAX_WIDTH,
      y2: MAX_HEIGHT,
    },
  });

  useChain([gridApi], [0, 1], 1500);
  return (
    <>
      <div className={'flex h-96 w-96 bg-black p-10'}>
        <svg viewBox={`0 0 ${MAX_WIDTH} ${MAX_HEIGHT}`}>
          <g>
            {gridSprings.map(({ x2 }, index) => (
              <animated.line
                x1={0}
                y1={index * 10 + OFFSET}
                x2={x2}
                y2={index * 10 + OFFSET}
                key={index}
                className={'stroke-white stroke-1'}
              />
            ))}
            {gridSprings.map(({ y2 }, index) => (
              <animated.line
                x1={index * 10 + OFFSET}
                y1={0}
                x2={index * 10 + OFFSET}
                y2={y2}
                key={index}
                className={'stroke-white stroke-1'}
              />
            ))}
          </g>
        </svg>
      </div>
    </>
  );
};

svgを利用して線を書いています。useTrailでは、useSpringを絶妙にずらしたものを複数作成してくれます。今回の場合は、再生にuseChainを使用しています。全部を同時に再生したい場合は、useSpringsが良い選択肢になります。useSpringsの場合では、すべてが勝手に起動するようにすることになります。比べてみてください。

import { animated, useSprings } from '@react-spring/web';

export const Cross = () => {
  const STROKE_WIDTH = 0.5;
  const OFFSET = STROKE_WIDTH / 2;
  const MAX_WIDTH = 100 + OFFSET * 2;
  const MAX_HEIGHT = 100 + OFFSET * 2;

  const [gridSprings] = useSprings(16, () => ({
    from: {
      x2: 0,
      y2: 0,
    },
    to: {
      x2: MAX_WIDTH,
      y2: MAX_HEIGHT,
    },
  }));

  return (
    <>
      <div className={'flex h-96 w-96 bg-black p-10'}>
        <svg viewBox={`0 0 ${MAX_WIDTH} ${MAX_HEIGHT}`}>
          <g>
            {gridSprings.map(({ x2 }, index) => (
              <animated.line
                x1={0}
                y1={index * 10 + OFFSET}
                x2={x2}
                y2={index * 10 + OFFSET}
                key={index}
                className={'stroke-white stroke-1'}
              />
            ))}
            {gridSprings.map(({ y2 }, index) => (
              <animated.line
                x1={index * 10 + OFFSET}
                y1={0}
                x2={index * 10 + OFFSET}
                y2={y2}
                key={index}
                className={'stroke-white stroke-1'}
              />
            ))}
          </g>
        </svg>
      </div>
    </>
  );
};

フェードイン・フェードアウト

アニメーションといえば、フェードインとフェードアウトですよね。サイトを訪れた時にフェードインするパターンとuseStateを起因としてフェードイン・フェードアウトを切り替えるパターンの2パターン実装しています。

import { useState } from 'react';

import { animated, useSpring } from '@react-spring/web';

export const Fade = () => {
  const fade = useSpring({ from: { opacity: 0 }, opacity: 1 });

  const [visible, setVisible] = useState(false);
  const fadeStyles = useSpring({ opacity: visible ? 1 : 0 });
  return (
    <div className="h-96 w-96">
      <animated.div style={fade} className="m-4 rounded bg-blue-200 p-4 text-lg">
        これはフェードインアニメーションとTailwindスタイリングが適用されたコンポーネントです。
      </animated.div>
      <animated.div style={fadeStyles}>I fade in and out</animated.div>
      <button onClick={() => setVisible(!visible)}>Toggle</button>
    </div>
  );
};

終わり

ども!やっとでアニメーションライブラリに手を出した龍ちゃんです。手を出そうと1年ぐらい尻込みしてやっとで手を出せました。今回は、同僚に初期調査を依頼してそこから説明を受けるというレアなタイプでの実装だったのですが、めちゃんこ助かりました。

アニメーションライブラリだったので、サムネイルもちょいとおしゃれにしています。色を使えばおしゃれになるというのは幻想ですね。色使うのって難しい!そんなFigmaも頑張っていきます。

ではまた!

これから何個かReact Spring系の記事を投稿する予定です。よろしくお願いします。前回記事はこちらです。

アバター画像
About 龍:Ryu 107 Articles
2022年入社で主にフロントエンドの業務でTailwindと遊ぶ日々。お酒とうまいご飯が好きで、運動がちょっと嫌いなエンジニアです。しゃべれるエンジニアを目指しておしゃべりとブログ執筆に注力中(業務もね)//
ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。


ご覧いただきありがとうございます。
ブログの最新情報はSNSでも発信しております。
ぜひTwitterのフォロー&Facebookページにいいねをお願い致します!



>> 雑誌等の執筆依頼を受付しております。
   ご希望の方はお気軽にお問い合わせください!

Be the first to comment

Leave a Reply

Your email address will not be published.


*


質問はこちら 閉じる