-
Notifications
You must be signed in to change notification settings - Fork 2
API design
Miklós Fazekas edited this page Nov 17, 2025
·
25 revisions
Suggested changes to current api:
-
#23. Allow
RiveViewto receivedataBindas prop instead of proceduralref.bindViewModelInstance. Also allow to query the bound view model instance withgetViewModelInstance. -
POC #19 Suspense:
- create
<RiveContext. Within theContextuseRiveFile from the same input could be cached. This would support both Suspense, and placing multiple rive view's to a list. Would also allow us to release memory of objects created by hooks within this context. - Suspense version of
useRiveFilewhich requires to be called from context. We can keep the current non suspense version, but would use the Suspense in most of the examples.
- create
-
#17 Decided to delay Allow
RiveViewfileprop to be either aRiveFileor aRiveFileInput(uri,require(..),bytearray) -
Feature: allow
RiveViewto write view model properties with prop updates:<RiveView values={Game: {RemainingTime: remainingTime}}}... > -
Feature: allow
RiveViewto listen to to view model properties changes with props:<RiveView listenToValueChange={Foo:{ Bar: (newValue) => console.log("value updated", newValue)}} />or<RiveView onValueChange={(propName, newValue) => console.log(...) > - Question: autoBind is that needed?! If user provides vmi binding, then we don't do autoBind, otherwise what choice we have?!
Since nitro view is new arch, let's build on newer features from react, like suspense
See useLoader hook from r3f source
<RivePlayer
file={{url:'https://cdn.rive.app/animations/vehicles.riv'}}
/>or (with suspense)
const file = useRiveFile({url: 'https://cdn.rive.app/animations/vehicles.riv'}}
<RivePlayer
file={file}
/>Note: Since suspense requires a cache, we don't want a global cache we'll need a <RiveContext>
const MyRiveComponent() {
const file = useRiveFile({url: 'https://cdn.rive.app/animations/vehicles.riv'}}
return (
<RivePlayer
file={file}
/>
)
}
...
<RiveContext>
<MyRiveComponent />
</RiveContext><RivePlayer
file={{url:'https://cdn.rive.app/animations/vehicles.riv'}}
customAssetLoader={{foo: require('....png'), bar: require('...png')}
/>or
const file = useRiveFile({url: 'https://cdn.rive.app/animations/vehicles.riv'}, {customAssetLoader: {foo: require('....png'), bar: require('...png')}}
// suspense: type file of file is `RiveFile` not `RiveFile | null`
<RivePlayer
file={file}
/>const [score, setScore] = useState()
<RivePlayer
file={{url:'https://cdn.rive.app/animations/vehicles.riv'}}
values={{['Button/State_1']: 'button name'}}
observeValues={{score: setScore}}
/>Limitations: only set + listen, but no read
const file = useRiveFile({url: 'https://cdn.rive.app/animations/vehicles.riv'}, {customAssetLoader: {foo: require('....png'), bar: require('...png')}}
const numSkin = useMemo(() => file.riveNumber('numSkin'), [file])
useEffect(() => numSkin.listen(i => console.log('numSkin is',i))
<RivePlayer
file={file}
state={state}
/>
<Button title="Bump" onPress={() => numSkin.set(numSkim.get() + 1))}const file = useRiveFile({url: 'https://cdn.rive.app/animations/vehicles.riv'}, {customAssetLoader: {foo: require('....png'), bar: require('...png')}}
const [numSkin, setNumSkin] = useRiveNumber(file, 'numSkin')
<RivePlayer
file={file}
state={state}
/>
<Button title="Bump" onPress={() => numSkin.set(numSkim.get() + 1))}- Is this summary correct?
RiveFile (.riv)
├── Artboard(s) [multiple, one default]
│ ├── StateMachine(s) [multiple, one default] // has ViewModelInstance bound
│ └── Graphics/Animations
├── ViewModel(s) [multiple, one default]
│ └── ViewModelInstance(s)
│ └── Properties [read/observed/set values]
└── Assets [fonts, images, audio] // either provided on load, or referenced and changed later
RivePlayer manages playback of a state machine in an artboard, with a view model instance bound to that state machine.
- ViewModelInstance autobinding?! Do ViewModels describe initial values?