Skip to content

Commit 91988ee

Browse files
committed
feat: add useViewModelInstance hook
1 parent 2a88413 commit 91988ee

3 files changed

Lines changed: 84 additions & 4 deletions

File tree

example/src/pages/MenuListExample.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
type RiveFile,
1616
useRiveFile,
1717
useRiveList,
18+
useViewModelInstance,
1819
} from '@rive-app/react-native';
1920
import { type Metadata } from '../helpers/metadata';
2021

@@ -38,10 +39,7 @@ export default function MenuListExample() {
3839

3940
function WithViewModelSetup({ file }: { file: RiveFile }) {
4041
const viewModel = useMemo(() => file.viewModelByName('main'), [file]);
41-
const instance = useMemo(
42-
() => viewModel?.createDefaultInstance(),
43-
[viewModel]
44-
);
42+
const instance = useViewModelInstance(viewModel);
4543

4644
if (!instance || !viewModel) {
4745
return (

src/hooks/useViewModelInstance.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { useState, useEffect } from 'react';
2+
import type { ViewModel, ViewModelInstance } from '../specs/ViewModel.nitro';
3+
4+
export interface UseViewModelInstanceParams {
5+
/**
6+
* Get a specifically named instance from the ViewModel.
7+
*/
8+
name?: string;
9+
/**
10+
* Get the default instance from the ViewModel.
11+
* @default true
12+
*/
13+
useDefault?: boolean;
14+
/**
15+
* Create a new (blank) instance from the ViewModel.
16+
*/
17+
useNew?: boolean;
18+
}
19+
20+
/**
21+
* Hook for getting a ViewModelInstance from a ViewModel.
22+
*
23+
* Resolution order:
24+
* 1. If `name` is provided, gets instance by name
25+
* 2. If `useNew` is true, creates a new instance
26+
* 3. Otherwise, gets the default instance
27+
*
28+
* @param viewModel - The ViewModel to get an instance from
29+
* @param params - Configuration for which instance to retrieve
30+
* @returns The ViewModelInstance or null if not found
31+
*
32+
* @example
33+
* ```tsx
34+
* const viewModel = file.viewModelByName('main');
35+
* const instance = useViewModelInstance(viewModel);
36+
* ```
37+
*
38+
* @example
39+
* ```tsx
40+
* // Create a new blank instance
41+
* const viewModel = file.viewModelByName('TodoItem');
42+
* const newInstance = useViewModelInstance(viewModel, { useNew: true });
43+
* ```
44+
*/
45+
export function useViewModelInstance(
46+
viewModel: ViewModel | null | undefined,
47+
params?: UseViewModelInstanceParams
48+
): ViewModelInstance | null {
49+
const [instance, setInstance] = useState<ViewModelInstance | null>(null);
50+
51+
const name = params?.name;
52+
const useDefault = params?.useDefault ?? true;
53+
const useNew = params?.useNew ?? false;
54+
55+
useEffect(() => {
56+
if (!viewModel) {
57+
setInstance(null);
58+
return;
59+
}
60+
61+
let vmi: ViewModelInstance | undefined;
62+
63+
if (name) {
64+
vmi = viewModel.createInstanceByName(name);
65+
} else if (useNew) {
66+
vmi = viewModel.createInstance();
67+
} else if (useDefault) {
68+
vmi = viewModel.createDefaultInstance();
69+
}
70+
71+
setInstance(vmi ?? null);
72+
73+
return () => {
74+
if (vmi) {
75+
vmi.dispose();
76+
}
77+
};
78+
}, [viewModel, name, useDefault, useNew]);
79+
80+
return instance;
81+
}

src/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ export { useRiveEnum } from './hooks/useRiveEnum';
4949
export { useRiveColor } from './hooks/useRiveColor';
5050
export { useRiveTrigger } from './hooks/useRiveTrigger';
5151
export { useRiveList } from './hooks/useRiveList';
52+
export { useViewModelInstance } from './hooks/useViewModelInstance';
5253
export { useRiveFile } from './hooks/useRiveFile';
5354
export { type RiveFileInput } from './hooks/useRiveFile';
5455
export { DataBindMode };

0 commit comments

Comments
 (0)