狀態機驅動 & 創造自然互動
在等待了整整一年之後 v9 終於進入 rc3 了
過去主流動的 Lib 像是 GSAP, Anime.js... 等動畫 lib 主要都是為了製作連續性複雜「動畫」而被設計出來的,所以當應用在 UI 互動甚至連續性操作的即時動態反饋,在 API 設計上往往並不是直接的滿足需求。
往往必須自己去做各種狀態對應的串接或中斷,導致開發上十分的不直感。
於是在這個以狀態機作為主流驅動的世界, 既然 UI 本身都是配合狀態在連動變化,那理所當然 UI 動畫也該跟著狀態補間連動才是。
...
import { a, useSpring } from "react-spring"
const ReactSpringCheckboxToggleDemo = ({ children }) => {
const [isOn, toggle] = useToggle(false)
// style 類似 react 的 state, 但不會觸發 react dom 的連帶更新,
// 而是自己獨立控管的樣式狀態機,來跟下面 a.{html_elements} 做連動狀態更新
const style = useSpring({ x: isOn ? 100 : 0 })
return (
<>
<input type="checkbox" value={isOn} onClick={toggle} />
<a.div style={style} className="ball">
{`<=`}
</a.div>
<>
)
}
上面談到的是 react-spring 狀態機所解決的問題,接著再來看另一個情境。
那就是使用者在「即時性操做」的「連續動態」上,舊有動畫庫的設計形式往往難以直接達成「自然的」反饋。
bring your components to "life" with simple spring animation primitives
讓使用者能對虛擬世界的操作與現實有所連結
簡單來說就是讓使用者自然界中熟悉的物理性帶入操作互動之中。
一般動畫庫多是用設定 ease + duration 的形式來調整動畫運作的形式,但 React-Spring 則是用上面的物理性參數來實現動態。 也就是說你不再是決定動畫運作的時間。
以上面的彈簧運動來說,在過去或許會用 repeat infinite 配上 ease-out 的形式來實現。
但也就相對難以進一步表現出物質界自然的衰減性。
// React-Spring v9
const ReactSpringDemo1 = ({ children }) => {
const [{ x }, animate] = useSpring(
{
x: 0,
config: {
mess: 2, // 質量
friction: 1, // 阻力
tension: 200, // 張力
},
},
[] // 傳一個 [] 是 v9 拿 setSpring 的新形式,也可以直接對 useSpring 傳入 function 的形式獲得
)
const handleAddInitVelocity = useCallback(() => {
x.stop() // 想藉由 velocity 為觸發給予動量必須先停止才能作用
animate({
x: 0,
config: { velocity: 1 },
})
}, [])
return (
<a.div style={{ x }} onClick={handleAddInitVelocity}>
Click
</a.div>
)
}
最早吸引我入坑的 Demo,互動性的實現!
完整為動態的使用場景而設計
React & JSX 形式對 THREE.js 實現更好管理的狀態機&組件設計模式
Paul Henschel 是 react-spring 的開創者
像上面這個 react-spring 下的子專案將 3D 繪圖產出的 gltf 轉成 jsx 的形式放進
react-three-fiber 去做進階互動
Alec Larson 是 v9 的主要維護者
v8 在功能上其實已經十分完整,v9 則是將整個 api 做了大重構,更增進了開發體驗。經過他接近一年努力,也完善更多使用情境的寫法支援。
兩個我最有感的:
const { x, y } = useSpring({ x: 0, y: 0 })
// v8
import { to } from "react-spring"
const transform = to([x, y], (x, y) => `translate(${x}px, ${y}px)`)
return <a.div style={{ transform }} />
// v9
return <a.div style={{ x, y }} />
// Chaining with an array
useSpring({
to: [
{ opacity: 1, config: { duration: 1000 } },
{ color: "red", delay: 1000 },
],
from: { opacity: 0, color: "black" },
})
// Chaining with an async function
useSpring({
to: async (next) => {
await next({ opacity: 1, config: { duration: 1000 } })
await next({ color: "red", delay: 1000 })
},
from: { opacity: 0, color: "black" },
})
其實這篇是算是綜合 逃避工作 & 想對 MDX 完整測試 & 慶祝期待已久v9 三個動機而寫成的哈哈...
react-spring 跟 GSAP 都是用的會讓人感動的工具,有這兩樣特性互補的神器真的是想做什麼都的心應手啊~!
最後~ 歡迎幫我下面按個心得~ 讓我知道有人讀完這篇了~感恩XD
