指南 · 01

值與 style

在元件中持有一個值,以 calc() 推導輸出,並選擇 CSS 變數寫入的位置。

持有一個值

useAnimatedValue(initial) 建立一個歸元件所有的 Value。可以用數字,也可以用 { x: 0, opacity: 1 } 這樣的紀錄,每個欄位都是獨立的值。

在一般的 style 中,Hook 的值是 var(--kkwa-…, initial) 這個標記。更新時會把變數寫到使用它的元素上,React 不會渲染。

正在準備範例…

以 calc() 推導

沒有緩動的內插,以及與常數的 add、subtract、multiply 或 divide,都會成為同一個變數的精確 calc() 運算式。它們由瀏覽器推導,不會每一格執行 JavaScript。

Slide.jsx
const progress = useAnimatedValue(0);

// A linear interpolation of a hook value is a calc() of the same CSS variable.
const x = progress.interpolate({ inputRange: [0, 1], outputRange: ['0px', '180px'] });
const half = multiply(progress, 0.5);

<div style={{ opacity: half, transform: `translateX(${x})` }} />;

正在準備範例…

顏色與自訂計算

顏色、帶緩動的內插、modulo、diffClamp 與 AnimatedComputed 無法寫成 calc()。useAnimatedCSS(node) 會為它們提供專屬的 CSS 變數,由 JavaScript 更新,生命週期與元件相同。

直接在 style 中使用這種節點會拋出例外,所以成本絕不會被藏起來。

Glow.jsx
const progress = useAnimatedValue(0);

// Colors and eased curves are not calc() expressions: give them their own CSS value.
const color = useAnimatedCSS(
  progress.interpolate({ inputRange: [0, 1], outputRange: ['#3d3bf3', '#22b8f0'] }),
);

<div style={{ background: color }} />;

讓 Hook 管理動畫配方

useAnimated(initial, factory, deps) 持有值,以及在工廠函式中同步宣告的所有控制器。掛載時開始、相依值改變時重新開始、卸載時停止。

若要由事件觸發播放,傳入 { autoStart: false },再對回傳的值呼叫 start()、stop() 或 reset()。

Intro.jsx
const intro = useAnimated(
  { opacity: 0, y: 24 },
  (value) => {
    parallel([
      timing(value.opacity, { toValue: 1, duration: 400 }),
      spring(value.y, { toValue: 0, stiffness: 220, damping: 20 }),
    ]);
  },
  [],
);

<section style={{ opacity: intro.opacity, transform: `translateY(calc(${intro.y} * 1px))` }} />;

寫入一次,作用於多個元素

預設情況下,每個在行內樣式中使用該值的元素都會收到這個變數。使用 scope 時,變數只會在容器上寫入一次並由子元素繼承——元素有數百個時,這是正確的選擇。

AnimatedProvider scope={ref} 為其下所有 Hook 值設定預設的 scope。

Field.jsx
const field = useRef(null);

// Written once on the field; every child that uses the value inherits it.
const wave = useAnimatedValue(0, { scope: field });

<div ref={field}>
  {items.map((item) => (
    <i key={item} style={{ transform: `rotate(calc(${wave} * 1turn))` }} />
  ))}
</div>;

在 JavaScript 中讀取值

getValue() 會回傳快照,不會讓 React 訂閱。useAnimatedListener(node, fn) 在每次變化時呼叫你,並在卸載時移除監聽器。適合 canvas 繪圖或數據分析,不要用於渲染。

搜尋

輸入關鍵字搜尋文件。