値の派生と応用
interpolateとinterpolateColorで1つの進捗を複数の表現へ展開し、clampやuseDerivedValueとあわせて値を組み立てる考え方を身につけます。
ここまでは1つの共有値を1つのスタイルに結びつけてきました。実際のUIでは、1つの入力から複数の見た目を同時に動かしたい場面がよくあります。スクロール量に応じて、透明度も位置も色もいっしょに変える、といった具合です。この章では、値を別の範囲へ変換するinterpolateと、そこから派生する道具を扱います。
interpolateで値を変換する
interpolateは、ある範囲の値を別の範囲へ線形に変換します。たとえば0から100まで動く値を、0から1の透明度へ移し替えられます。

1つの入力を変換し、複数の見た目へ枝分かれさせるのが値の派生の基本です。
const animatedStyle = useAnimatedStyle(() => ({
opacity: interpolate(sv.value, [0, 100], [0, 1]),
}));
引数は4つです。第1引数valueが変換したい値、第2引数inputが入力範囲、第3引数outputが出力範囲です。outputはinputと同じ数以上の点を持つ必要があります。第4引数extrapolateは、valueが入力範囲を越えたときの振る舞いを決めます。
extrapolateには3種類あります。
Extrapolation.EXTEND範囲の外側も直線の延長で予測する(既定)Extrapolation.CLAMP出力範囲の端で値を止めるExtrapolation.IDENTITY入力値をそのまま返す
次のプレイグラウンドは、1つのprogressスライダーから複数のスタイルを同時に動かします。progressを0から1と見立て、透明度・水平位置・回転角・背景色をそれぞれ別の範囲へ変換しています。スライダーを動かすと、四角形が横に移動しながら回転し、色が変わり、少しずつはっきり見えてきます。
「コード」タブを見ると、同じprogressからinterpolateとinterpolateColorをいくつも呼び出しているのが分かります。入力は1つ、出力は複数。これが値を派生させる基本の形です。
interpolateColorで色を変換する
数値のinterpolateとよく似た形で、色を変換するのがinterpolateColorです。出力に色の文字列を並べると、その間をなめらかに補間します。
const animatedStyle = useAnimatedStyle(() => ({
backgroundColor: interpolateColor(progress.value, [0, 1], ["red", "green"]),
}));
出力の色は'red'や'#ff0000'、'rgba(255, 0, 0, 0.5)'のような文字列で指定します。第4引数colorSpaceで補間に使う色空間を'RGB'・'HSV'・'LAB'から選べます。既定は'RGB'です。戻り値はrgba(r, g, b, a)形式の文字列になります。
clampで値を挟み込む
clampは値を指定した範囲に収めるユーティリティです。
const result = clamp(sv.value, 0, 100);
valueがminとmaxの間ならそのまま返し、下回ればmin、上回ればmaxを返します。ドラッグできる要素を画面の外へ出さないようにする、といった場面で役立ちます。interpolateのExtrapolation.CLAMPが範囲の端で止めるのと似ていますが、clampは変換ではなく、単純な挟み込みだけを行います。
useDerivedValueで値を派生させる
interpolateで作った値を、独立した共有値として持っておきたいこともあります。そのためのフックがuseDerivedValueです。既存の共有値をもとに、新しい共有値を反応性を保ったまま作ります。
const derivedValue = useDerivedValue(() => sv.value * 50, [sv]);
第1引数updaterは、共有値やstateから組み立てた値を返す関数です。中で使っている共有値やstateのどれかが変わるたびに呼び直されます。第2引数は依存配列で、web向けにBabelプラグインを使わない構成のときにだけ関係します。戻り値は読み取り専用の共有値です。派生させた値なので、こちら側から書き換えることは想定されていません。
次のデモは、1つのscaleをループさせ、そこから回転角を派生させています。左の丸はscaleで拡大縮小し、右の四角はscaleから派生したrotateで回転します。1つの値の変化が、2つの見た目へ波及しているのが見て取れます。
useAnimatedPropsで進捗をpropsへ
派生させた値をスタイルではなくpropsへ渡したいときは、第2章で触れたuseAnimatedPropsを使います。たとえば進捗に応じてSVGの円の半径を変える、といった使い方です。
const animatedProps = useAnimatedProps(() => ({
r: interpolate(progress.value, [0, 1], [10, 40]),
}));
<AnimatedCircle cx="50%" cy="50%" fill="#b58df1" animatedProps={animatedProps} />;
useAnimatedPropsのupdaterはアニメーションさせたいpropsのオブジェクトを返します。useAnimatedStyleと同じく.valueにアクセスでき、依存配列の扱いも共通です。ここでもinterpolateで進捗を半径へ変換しています。
この例はreact-native-svgに依存するため、本書のデモ環境では動くデモにできません。コード例として示すにとどめます。SVGを含む実践的な組み合わせは、巻末のSVGのアニメーションで取り上げます。
この章のまとめ
interpolateは値を別の範囲へ線形に変換し、extrapolateで範囲外の扱いを決めますinterpolateColorは同じ考え方で色を補間しますclampは値を範囲に収める単純な挟み込みですuseDerivedValueは既存の共有値から読み取り専用の共有値を派生させます- これらを組み合わせると、1つの入力を複数の表現へ展開できます
第2部はここまでです。共有値・スタイル・アニメーション関数・モディファイア・値の派生と、Reanimatedの基本がひととおりそろいました。第3部では、ここで学んだ道具をジェスチャーやレイアウトアニメーションと結びつけ、実践的なインタラクションを組み立てていきます。