Skip to content

Commit 90ea02f

Browse files
committed
feat(example): add Data Binding (expapi) exerciser using async VM API
Mirror of the existing Data Binding exerciser but with WithViewModelSetup replaced to use `defaultArtboardViewModelAsync()` and `createDefaultInstanceAsync()` instead of the deprecated sync counterparts. Useful for verifying the async path produces identical visual results.
1 parent 798340d commit 90ea02f

1 file changed

Lines changed: 163 additions & 0 deletions

File tree

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
2+
import { useEffect, useState } from 'react';
3+
import {
4+
Fit,
5+
RiveView,
6+
useRiveNumber,
7+
type ViewModelInstance,
8+
type RiveFile,
9+
useRiveString,
10+
useRiveColor,
11+
useRiveTrigger,
12+
useRiveFile,
13+
} from '@rive-app/react-native';
14+
import { type Metadata } from '../shared/metadata';
15+
16+
export default function WithRiveFile() {
17+
const { riveFile, isLoading, error } = useRiveFile(
18+
require('../../assets/rive/rewards.riv')
19+
);
20+
21+
return (
22+
<View style={styles.container}>
23+
<View style={styles.riveContainer}>
24+
{isLoading ? (
25+
<ActivityIndicator size="large" color="#0000ff" />
26+
) : riveFile ? (
27+
<WithViewModelSetup file={riveFile} />
28+
) : (
29+
<Text style={styles.errorText}>{error || 'Unexpected error'}</Text>
30+
)}
31+
</View>
32+
</View>
33+
);
34+
}
35+
36+
function WithViewModelSetup({ file }: { file: RiveFile }) {
37+
const [instance, setInstance] = useState<ViewModelInstance | undefined>(
38+
undefined
39+
);
40+
const [setupError, setSetupError] = useState<string | undefined>(undefined);
41+
42+
useEffect(() => {
43+
let cancelled = false;
44+
45+
async function setup() {
46+
const viewModel = await file.defaultArtboardViewModelAsync();
47+
if (cancelled) return;
48+
49+
if (!viewModel) {
50+
setSetupError('No view model found');
51+
return;
52+
}
53+
54+
const vmi = await viewModel.createDefaultInstanceAsync();
55+
if (cancelled) return;
56+
57+
if (!vmi) {
58+
setSetupError('Failed to create view model instance');
59+
return;
60+
}
61+
62+
setInstance(vmi);
63+
}
64+
65+
setup().catch((e: unknown) => {
66+
if (!cancelled) {
67+
setSetupError(String(e));
68+
}
69+
});
70+
71+
return () => {
72+
cancelled = true;
73+
};
74+
}, [file]);
75+
76+
if (setupError) {
77+
return <Text style={styles.errorText}>{setupError}</Text>;
78+
}
79+
80+
if (!instance) {
81+
return <ActivityIndicator size="large" color="#0000ff" />;
82+
}
83+
84+
return <DataBindingExample instance={instance} file={file} />;
85+
}
86+
87+
function DataBindingExample({
88+
instance,
89+
file,
90+
}: {
91+
instance: ViewModelInstance;
92+
file: RiveFile;
93+
}) {
94+
const { error: coinValueError } = useRiveNumber('Coin/Item_Value', instance);
95+
96+
if (coinValueError) {
97+
console.error('coinValueError', coinValueError);
98+
}
99+
100+
const { setValue: setButtonText } = useRiveString('Button/State_1', instance);
101+
102+
const { setValue: setBarColor, error: barColorError } = useRiveColor(
103+
'Energy_Bar/Bar_Color',
104+
instance
105+
);
106+
107+
if (barColorError) {
108+
console.error('barColorError', barColorError);
109+
}
110+
111+
const { error: triggerError } = useRiveTrigger('Button/Pressed', instance, {
112+
onTrigger: () => {
113+
console.log('Button pressed');
114+
},
115+
});
116+
117+
if (triggerError) {
118+
console.error('triggerError', triggerError);
119+
}
120+
121+
useEffect(() => {
122+
setButtonText("Let's go!");
123+
setBarColor('#0000FF');
124+
}, [setBarColor, setButtonText]);
125+
126+
return (
127+
<RiveView
128+
style={styles.rive}
129+
autoPlay={true}
130+
dataBind={instance}
131+
fit={Fit.Layout}
132+
layoutScaleFactor={1}
133+
file={file}
134+
/>
135+
);
136+
}
137+
138+
WithRiveFile.metadata = {
139+
name: 'Data Binding (expapi)',
140+
description:
141+
'Same as Data Binding but uses the async API (defaultArtboardViewModelAsync / createDefaultInstanceAsync)',
142+
} satisfies Metadata;
143+
144+
const styles = StyleSheet.create({
145+
container: {
146+
flex: 1,
147+
backgroundColor: '#fff',
148+
},
149+
riveContainer: {
150+
flex: 1,
151+
backgroundColor: '#f5f5f5',
152+
},
153+
rive: {
154+
flex: 1,
155+
width: '100%',
156+
height: '100%',
157+
},
158+
errorText: {
159+
color: 'red',
160+
textAlign: 'center',
161+
padding: 20,
162+
},
163+
});

0 commit comments

Comments
 (0)