ども!l今回はReact Springを用いて単一コンポーネントに連続でアニメーションを適応する方法について解説しています。まるでスプラのリザルト画面的なアニメーションを実装する方法を目指してみました。若干動きがぎこちないですが、ひとまずという感じで執筆しています。小さいところからアニメーションを用いたUX改善を始めましょう。
はじめます
ども!お家から30分圏内で行ける温泉を探し回っている龍ちゃんです。意外といける温泉が多くてニヤニヤしています。温泉でコーディングできる施設なんてないかな~と思っていますが、これはもう旅館に行くしかないですね。
さて今回もReact Springを使った内容を深ぼっていきたいと思います。今回取り扱うシナリオは、「同一のコンポーネントに複数のアニメーションを連続で適応する」になります。
それではさくっと始めていきましょう。セットアップに関しては、前回の記事で解説入れています。
本題
今回のシナリオをどこで使ったかについては、以下の動画を見てもらえればかなと思います。こちらは、OSC福岡で作成したサイトになります。
「スプラ〇ゥーン」のリザルト画面をイメージして作成しました。もっと滑らかになるつもりだったのですが、ひとまずここが限界かなと思います。
環境とセットアップ
それでは、セットアップと使用方法についてまとめていきます。インストール自体は、安心コマンド一発になります。
yarn add @react-spring/web
あとは、要素の部分を以下に変更することで動作します。
import { animated } from '@react-spring/web'
export default function MyComponent() {
return (
<animated.div
style={
<-- アニメーションの定義をここで書くとええ感じの動作する -->
}
/>
)
}
これだけでアニメーションを定義することができるので、非常に楽で便利です。環境は「Tailwind CSS」を利用しています。
連続アニメーション適応
単一コンポーネントに複数のアニメーションを適応する方法は、一つのアニメーションの後にAPIで適応する方法などもありそうです。今回は、事前に複数の定義を付けておく方法で対応していきます。to
の部分で順次定義を記載しておくことでアニメーションが連続で実行されます。
const ratioAnimationPropsA = useSpring({
from: { width: '0%' },
to: async (next) => {
await next({ tension: 200, friction: 20, config: { duration: 200 } });
for (let i = 0; i < 5; i++) {
await next({
width: `${Math.random() * 5 + 10}%`,
config: { tension: 200, friction: 20, duration: 500 },
});
}
await next({
width: `${ratioA}%`,
config: { duration: 100 },
});
},
});
スプ〇トゥーン的なアニメーション
サンプル動画で作成したプログラムが以下になります。引数として2つの値を渡すことで、値を計算してプログラムがスプラ〇ゥーン的なアニメーションを作成してくれます。
import { animated, useSpring } from '@react-spring/web';
interface TripleGraphProps {
valueA: number;
valueB: number;
}
const calculatePercentages = (A: number, B: number): { ratioA: number; ratioB: number } => {
const total = A + B;
if (total <= 0) return { ratioA: 0, ratioB: 0 };
const ratioMushrooms = (A / total) * 100;
const ratioBamboo = (B / total) * 100;
return { ratioA: ratioMushrooms, ratioB: ratioBamboo };
};
export const BarHorizontal = (props: TripleGraphProps) => {
const { valueA, valueB } = props;
const { ratioA, ratioB } = calculatePercentages(valueA, valueB);
const ratioAnimationPropsA = useSpring({
from: { width: '0%' },
to: async (next) => {
await next({ tension: 200, friction: 20, config: { duration: 200 } });
for (let i = 0; i < 5; i++) {
await next({
width: `${Math.random() * 5 + 10}%`,
config: { tension: 200, friction: 20, duration: 500 },
});
}
await next({
width: `${ratioA}%`,
config: { duration: 100 },
});
},
});
const ratioAnimationPropsB = useSpring({
from: { width: '0%' },
to: async (next) => {
await next({ tension: 200, friction: 20, config: { duration: 200 } });
for (let i = 0; i < 5; i++) {
await next({
width: `${Math.random() * 5 + 10}%`,
config: { tension: 200, friction: 20, duration: 500 },
});
}
await next({
width: `${ratioB}%`,
config: { duration: 100 },
});
},
});
return (
<div className="flex w-full flex-row items-center gap-2 py-4 shadow">
<div className="relative flex h-44 w-full flex-row justify-between rounded-md shadow">
<animated.div className={'bg-[#F59E0B]'} style={ratioAnimationPropsA} />
<animated.div className={' bg-[#22C55E]'} style={ratioAnimationPropsB} />
<span className="absolute left-1/2 top-0 h-full w-2 -translate-x-1/2 bg-main" />
</div>
</div>
);
};
ひとまず適当にコピペしてもらえれば動くと思うので参考にしてみてください。
おわります
今回のプログラムは、同僚が事前調査をしてくれていたのでカスタマイズするだけで実装できました。すごくありがたいですね。ブログのネタを共有してくれる同僚とChatGPTには感謝しかありません。ちょっとしたUX改善ができるのが、アニメーションのいいところですがデザイン性は気を使わないといけないですね。あんまり頭の中にストックがないのがつらいところなので、サンプルを探すところから始まりそうです。
すんばらしいことにReact Spring Exampleが質の良いサンプルが転がっています。ここを見て学習をしていきましょう。
最近ChatGPTで、単線描画を出力させるのにはまっています。かわいいですよね。
React Springの記事はこちらになります。