跳到主要内容

迁移指南

迁移到 v0.4.0+

此版本改进了 hooks 的错误透明度和加载语义,为异步实验性运行时做准备。

useViewModelInstance 返回 { instance, error }

该 hook 现在返回一个可区分联合类型,而不是 ViewModelInstance | null

  • { instance: undefined, error: null } — 加载中(源未就绪)
  • { instance: ViewModelInstance, error: null } — 成功
  • { instance: null, error: null } — 已解析,未找到 ViewModel
  • { instance: null, error: Error } — 查找失败

新版 API

const { riveFile } = useRiveFile(require('./animation.riv'));
const { instance, error } = useViewModelInstance(riveFile);

if (error) return <Text>{error.message}</Text>;
if (!instance) return <ActivityIndicator />;
return <RiveView file={riveFile} dataBind={instance} />;

旧版 API

const { riveFile } = useRiveFile(require('./animation.riv'));
const instance = useViewModelInstance(riveFile);

if (!instance) return <ActivityIndicator />;
return <RiveView file={riveFile} dataBind={instance} />;

useRiveFile Error 现在是 Error

error 字段现在是一个 Error 对象而不是 string,并且 riveFile 在加载期间为 undefined(之前是 null)。isLoading 保留以便使用。

新版 API

const { riveFile, isLoading, error } = useRiveFile(require('./animation.riv'));

if (error) return <Text>{error.message}</Text>;

旧版 API

const { riveFile, isLoading, error } = useRiveFile(require('./animation.riv'));

if (error) return <Text>{error}</Text>;

属性 Hooks 从 undefined 开始

useRiveNumberuseRiveStringuseRiveBooleanuseRiveColoruseRiveEnum 在挂载时不再同步读取 property.value。值初始为 undefined,并通过属性监听器到达。

const { value: health } = useRiveNumber('health', instance);

// 第一次渲染时 health 为 undefined — 使用前需守卫
<Text>{health !== undefined ? health.toFixed(2) : '...'}</Text>

// 在更新器函数中守卫
setHealth((prev) => (prev ?? 0) + 1);

快速参考

之前替换
const instance = useViewModelInstance(file)const { instance, error } = useViewModelInstance(file)
{error}(在 JSX 中,来自 useRiveFile{error?.message}
riveFile === null(加载检查)riveFile === undefined 或使用 isLoading
health 在首次渲染时同步可用undefined 做守卫:health !== undefined ? ... : ...

迁移到 Async API(v0.3.2+)

此版本引入了异步优先 API,为新的实验性 Rive 运行时做准备。阻塞 JS 线程的同步方法已被弃用,替换为异步等效方法。状态机输入和文本运行方法已被弃用,推荐使用数据绑定,并将在实验性运行时中完全移除(因此也将在即将推出的 @rive-app/react-native 版本中移除)。

变化内容

  • 异步方法替换了所有同步的 ViewModel 和属性访问器
  • 基于名称的访问替换了基于计数/索引的 ViewModel 和画板查找
  • getValueAsync() / set() 替换了 property.value 用于读取和写入属性
  • 状态机输入、文本运行和事件已被弃用,将在实验性运行时中移除 — 请改用数据绑定

迁移步骤

1. ViewModel 访问

新版 API:

const names = await file.getViewModelNamesAsync();
const vm = await file.viewModelByNameAsync('Person');
const defaultVM = await file.defaultArtboardViewModelAsync();

已弃用 API:

const count = file.viewModelCount;
const vm = file.viewModelByName('Person');
const defaultVM = file.defaultArtboardViewModel();

2. 实例创建

新版 API:

const instance = await vm.createDefaultInstanceAsync();
const named = await vm.createInstanceByNameAsync('player1');
const blank = await vm.createBlankInstanceAsync();

已弃用 API:

const instance = vm.createDefaultInstance();
const named = vm.createInstanceByName('player1');
const blank = vm.createInstance();

useViewModelInstance hook 为您处理 ViewModel 解析和实例创建 — 在大多数情况下,您不需要直接调用这些方法。

3. 属性值访问

新版 API:

const num = await prop.getValueAsync();
prop.set(42);

已弃用 API:

const num = prop.value;
prop.value = 42;

4. 嵌套 ViewModelInstance 访问

新版 API:

const nested = await instance.viewModelAsync('Header');

已弃用 API:

const nested = instance.viewModel('Header');

5. 列表属性访问

新版 API:

const len = await listProp.getLengthAsync();
const item = await listProp.getInstanceAtAsync(0);

已弃用 API:

const len = listProp.length;
const item = listProp.getInstanceAt(0);

6. 画板访问

新版 API:

const count = await file.getArtboardCountAsync();
const names = await file.getArtboardNamesAsync();

已弃用 API:

const count = file.artboardCount;
const names = file.artboardNames;

7. 异步设置模式

用于 ViewModel 设置的同步 useMemo 链应该替换为 useState + useEffect,或者用 useViewModelInstance hook 简化。

useViewModelInstance(推荐)

const { riveFile } = useRiveFile(require('./animation.riv'));
const { instance } = useViewModelInstance(riveFile);

const { value: health, setValue: setHealth } = useRiveNumber(
'health',
instance
);

if (!instance) return <ActivityIndicator />;
return <RiveView file={riveFile} dataBind={instance} />;

手动异步设置

const { riveFile } = useRiveFile(require('./animation.riv'));
const [instance, setInstance] = useState<ViewModelInstance>();

useEffect(() => {
if (!riveFile) return;
let cancelled = false;
(async () => {
const vm = await riveFile.defaultArtboardViewModelAsync();
const vmi = await vm?.createDefaultInstanceAsync();
if (!cancelled) setInstance(vmi ?? undefined);
})();
return () => { cancelled = true; };
}, [riveFile]);

已弃用的同步模式

function Setup({ file }) {
const vm = useMemo(() => file.defaultArtboardViewModel(), [file]);
const instance = useMemo(
() => vm?.createDefaultInstance(),
[vm]
);
if (!instance) return null;
return <MyComponent instance={instance} file={file} />;
}

快速参考

已弃用替换
file.viewModelByName(name)await file.viewModelByNameAsync(name)
file.defaultArtboardViewModel()await file.defaultArtboardViewModelAsync()
file.viewModelCount(await file.getViewModelNamesAsync()).length
file.viewModelByIndex(i)await file.viewModelByNameAsync(name)
file.artboardCount / artboardNamesawait file.getArtboardCountAsync() / getArtboardNamesAsync()
vm.createDefaultInstance()await vm.createDefaultInstanceAsync()
vm.createInstanceByName(name)await vm.createInstanceByNameAsync(name)
vm.createInstance()await vm.createBlankInstanceAsync()
instance.viewModel(path)await instance.viewModelAsync(path)
listProp.lengthawait listProp.getLengthAsync()
listProp.getInstanceAt(i)await listProp.getInstanceAtAsync(i)
prop.value(读取)await prop.getValueAsync()
prop.value = x(写入)prop.set(x)

平台注意事项

限制详情
replaceViewModel()Android 上空操作。iOS 上有效。
图像/列表属性上的 addListener()两个平台上均为空操作。改用 getLengthAsync() 轮询。
addInstanceAt() / swap() 返回值iOS 上始终为 true。Android 返回正确值。
instanceName除通过 createInstanceByNameAsync() 创建的实例外,为空字符串。
Android 上的 defaultArtboardViewModel()使用启发式方法。建议使用带有显式名称的 viewModelByNameAsync(name)

v0.1.0 迁移到 v0.2.0

此更改更新到 Nitro 的新主要版本以解决视图回收问题。详情请参见发布说明

唯一需要的更改是更新应用中使用的 Nitro 版本。


rive-react-native 迁移到 @rive-app/react-native

新版 Rive React Native 运行时(@rive-app/react-native)是使用 Nitro Modules 构建的完全重写版本,提供更好的性能和更好的 React Native 集成。

您的所有 Rive 图形看起来和功能仍将与之前一样。

新特性

RiveFile 所有权: 您现在通过 useRiveFile hook 拥有 RiveFile 对象,支持文件缓存、从一个文件创建多个实例以及更好的资源管理。

// 旧版: 文件内部管理
<Rive url="https://cdn.rive.app/animations/vehicles.riv" />

// 新版: 您拥有 RiveFile
const { riveFile } = useRiveFile(require("./vehicles.riv"));
<RiveView file={riveFile} />

增强的数据绑定: 直接访问 ViewModelViewModelInstance 对象,支持初始化 hooks、多个实例以及所有属性类型(列表、图像、画板)。

// 旧版: hooks 接受 riveRef,返回元组
const [setRiveRef, riveRef] = useRive();
const [health, setHealth] = useRiveNumber(riveRef, "health");

// 新版: hooks 接受 viewModelInstance,返回对象
const { instance: viewModelInstance } = useViewModelInstance(riveFile);
const { value: health, setValue: setHealth } = useRiveNumber(
"health",
viewModelInstance
);

改进的错误处理: 错误处理得到改进。参见错误处理文档了解更多信息。

系统要求

  • React Native:0.78+(推荐 0.79+)
  • Expo SDK:53+(Expo 用户)
  • iOS:15.1+
  • Android:SDK 24+
  • Xcode:16.4+
  • JDK:17+
  • Nitro Modules:0.25.2+

迁移步骤

1. 安装

npm uninstall rive-react-native
npm install @rive-app/react-native react-native-nitro-modules

react-native-nitro-modules 是必需的,因为此库依赖于 Nitro Modules

2. 更新导入

// 旧版
import Rive from "rive-react-native";

// 新版
import { RiveView } from "@rive-app/react-native";

3. 加载 Rive 文件

新版运行时:

const { riveFile, isLoading, error } = useRiveFile(require('./animation.riv'));
// 也支持: URL 字符串、资源名称或 ArrayBuffer

return <RiveView file={riveFile} style={{ width: 400, height: 400 }} />;

旧版运行时:

<Rive source={require('./animation.riv')} />
// 也支持: url 或 resourceName 属性

参见加载 Rive 文件了解更多信息。

4. 组件迁移

新版运行时:

<RiveView
file={riveFile}
artboardName="MainArtboard"
stateMachineName="State Machine 1"
fit={Fit.Contain}
autoPlay={true}
style={{ width: 400, height: 400 }}
/>

旧版运行时:

<Rive
url="https://cdn.rive.app/animations/vehicles.riv"
artboardName="MainArtboard"
stateMachineName="State Machine 1"
fit={Fit.Contain}
autoplay={true}
style={{ width: 400, height: 400 }}
/>

参见 React Native 运行时属性文档了解更多信息。

5. 视图引用迁移

新版运行时:

const { riveViewRef, setHybridRef } = useRive();

riveViewRef?.play();
riveViewRef?.pause();

<RiveView hybridRef={setHybridRef} file={riveFile} />

旧版运行时:

const [setRiveRef, riveRef] = useRive();

riveRef?.play();
riveRef?.pause();

<Rive ref={setRiveRef} url="..." />

参见 Rive ref 方法了解更多信息。

6. 状态机输入(已弃用)

⚠️ 这些方法已弃用。请迁移到数据绑定

新版运行时:

riveViewRef?.setNumberInputValue('level', 5);
riveViewRef?.setBooleanInputValue('isActive', true);
riveViewRef?.triggerInput('buttonPressed');

旧版运行时:

riveRef.current?.setInputState('State Machine 1', 'level', 5);
riveRef.current?.setInputState('State Machine 1', 'isActive', true);
riveRef.current?.fireState('State Machine 1', 'buttonPressed');

参见状态机输入了解更多信息。

7. Rive 事件(已弃用)

⚠️ 这些方法已弃用。请改用数据绑定触发器

新版运行时:

useEffect(() => {
const handleEvent = (event: RiveEvent) => console.log(event);
riveViewRef?.onEventListener(handleEvent);
return () => riveViewRef?.removeEventListeners();
}, [riveViewRef]);

旧版运行时:

<Rive
onRiveEventReceived={(event) => console.log(event)}
url="..."
/>

参见运行时事件了解更多信息。

8. 数据绑定

新版运行时通过让您直接访问 ViewModelInstance 对象显著改进了数据绑定。这支持:

  • 初始化 hooks — 在渲染前使用 onInit 回调设置初始属性值
  • 多个实例 — 从同一个文件创建和管理多个视图模型实例
  • 高级属性类型 — 完全支持列表、图像、画板和嵌套视图模型
  • 更好的 React 集成 — 属性 hooks 与 React 状态和生命周期无缝集成

主要 API 变化:

  • 属性 hooks 接受 viewModelInstance 而不是 riveRef
  • Hooks 返回对象而不是元组
  • 参数交换:(path, viewModelInstance)(riveRef, path)

新版运行时:

const { riveFile } = useRiveFile(require('./animation.riv'));
const { instance: viewModelInstance } = useViewModelInstance(riveFile);

const { value: health, setValue: setHealth } = useRiveNumber('health', viewModelInstance);
const { value: name, setName } = useRiveString('Player/Name', viewModelInstance);
const { trigger } = useRiveTrigger('gameOver', viewModelInstance, {
onTrigger: () => console.log('Game Over!')
});

<RiveView file={riveFile} dataBind={viewModelInstance} />

旧版运行时:

const [setRiveRef, riveRef] = useRive();

const [health, setHealth] = useRiveNumber(riveRef, 'health');
const [name, setName] = useRiveString(riveRef, 'Player/Name');
useRiveTrigger(riveRef, 'gameOver', () => console.log('Game Over!'));

<Rive ref={setRiveRef} resourceName="animation" dataBinding={AutoBind(true)} />

参见 React Native 数据绑定了解更多信息。

9. 带外资源

新版运行时:

const { riveFile } = useRiveFile(
require('./animation.riv'),
{
referencedAssets: {
'Inter-594377': {
source: require('./fonts/Inter-594377.ttf'),
},
'my-image': {
source: { uri: 'https://example.com/image.png' },
},
},
}
);

旧版运行时:

<Rive
url="..."
referencedAssets={{
'Inter-594377': {
source: require('./fonts/Inter-594377.ttf'),
},
}}
/>

参见加载资源了解更多信息。

10. 文本运行更新(已弃用)

⚠️ 直接文本运行方法(.setTextRunValue().getTextRunValue())已弃用。请迁移到数据绑定字符串。

数据绑定(推荐):

const { value: playerName, setValue: setPlayerName } = useRiveString('playerName', viewModelInstance);
setPlayerName('John Doe');

新版运行时(已弃用):

// 新版运行时仍像旧版运行时一样支持文本运行方法
riveViewRef?.setTextRunValue('playerName', 'John Doe');
const name = riveViewRef?.getTextRunValue('playerName');

旧版运行时:

riveRef.current?.setTextRunValue('playerName', 'John Doe');

参见文本运行了解更多信息。

11. 回调

新版运行时:

<RiveView
file={riveFile}
onError={(error) => console.error('Rive error:', error)}
/>

// 对于状态变化,使用数据绑定监听器。例如,触发器:
const { trigger } = useRiveTrigger('onStateChange', viewModelInstance, {
onTrigger: () => console.log('State changed')
});

旧版运行时:

<Rive
onPlay={(name, isSM) => console.log('Playing:', name)}
onPause={(name, isSM) => console.log('Paused:', name)}
onStateChanged={(sm, state) => console.log('State changed:', state)}
onError={(error) => console.error('Error:', error)}
/>

参见数据绑定了解更多信息。

获取帮助

如果遇到问题:

  1. 查看新版运行时文档
  2. 查阅数据绑定指南
  3. 参见示例应用
  4. 访问 Rive 社区论坛
  5. GitHub 上报告问题