rive-app / rive-app/rive-react-native
Problem using rive with flatlist
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 783
- Forks
- 81
- Avg merge
- 3d 6h
- Merged PRs (30d)
- 3
Description
Description
I've encountered a performance issue when using multiple Rive components within a FlashList (from @shopify/flash-list) in a React Native app. The app experiences significant delays during initial loading and scrolling, causing intermittent freezes. The bottleneck appears to stem from the simultaneous initialization of multiple Rive instances, each loading the same .riv file (excited_button.riv) with independent states. Even with FlashList's virtualization, the app becomes unresponsive when rendering more than a few items, suggesting that rive-react-native might not efficiently cache or manage resource loading for multiple instances.
Provide a Repro
Below is a minimal code snippet demonstrating how Rive is used within a list item component. Each item in the FlashList renders its own Rive component with a unique ref to maintain independent animation states (Level and Press).
import { useEffect, useRef } from 'react';
import { TouchableOpacity, View } from 'react-native';
import Rive, { type RiveRef } from 'rive-react-native';
import styled from 'styled-components/native';
import { FlashList } from '@shopify/flash-list';
const ListItem = ({ item, onExcitedCountPressed }) => {
const riveRef = useRef<RiveRef>(null);
useEffect(() => {
// Set initial animation state
setTimeout(() => {
riveRef.current?.setInputState('Excited Button', 'Level', item.level);
}, 60);
}, [item.level]);
const handlePress = () => {
riveRef.current?.fireState('Excited Button', 'Press');
onExcitedCountPressed(item.id);
};
return (
<Container>
<StyledRive
resourceName="excited_button"
artboardName="Artboard"
stateMachineName="Excited Button"
ref={riveRef}
/>
<RiveTouchableOpacity
hitSlop={{ top: 8, right: 8, left: 8, bottom: 8 }}
onPress={handlePress}
/>
{/* Other UI elements */}
</Container>
);
};
const ListComponent = ({ data }) => (
<FlashList
data={data}
renderItem={({ item }) => (
<ListItem item={item} onExcitedCountPressed={console.log} />
)}
estimatedItemSize={74}
initialNumToRender={5}
keyExtractor={item => item.id}
/>
);
const Container = styled.View`
min-height: 74px;
`;
const StyledRive = styled(Rive)`
width: 32px;
height: 32px;
`;
const RiveTouchableOpacity = styled(TouchableOpacity)`
position: absolute;
top: 8px;
width: 32px;
height: 100%;
`;
Unfortunately, I cannot provide a full GitHub repository or ZIP archive as the project is private. The issue occurs consistently when rendering 10+ items in the FlashList, each with its own Rive instance.
Source .riv/.rev file
Due to project constraints, I cannot attach the excited_button.riv file or its source .rev file here. The .riv file contains a state machine (Excited Button) with a Level input and a Press trigger, used to animate a button based on user interaction.
Expected behavior
I expect rive-react-native to efficiently handle multiple Rive instances within a virtualized list (e.g., FlashList) without causing significant performance degradation. Ideally:
- The initial loading of the
.rivfile should be cached and reused across all instances to minimize redundant resource loading. - Scrolling through the list should remain smooth, with minimal frame drops or freezes, even with 20-30 items.
- Each
Riveinstance should maintain its independent state (e.g.,Levelvalue) without impacting performance.
Screenshots
https://github.com/user-attachments/assets/72eb778d-ad17-48cf-8718-9930c1522b51
Device & Versions
- Device: All iOS simulators and devices including Android
- OS: iOS 18.2, Android SDK API Level 35
- NPM Version: 10.8.2
- rive-react-native Version: 7.2.0
- React Native Version: 0.74.5
- FlashList Version: 1.6.4
Additional context
- The app uses a single
.rivfile (excited_button.riv) across all list items, but each item needs its own animation state based on anexcitedCountvalue mapped to aLevelinput. - Even with FlashList's
initialNumToRenderset to 5, the initial load is slow, and scrolling introduces noticeable bottlenecks as moreRivecomponents enter the viewport. - I’ve tried delaying the
setInputStatecall withsetTimeoutandInteractionManager.runAfterInteractions, but the performance issue persists, likely due to the overhead of initializing multipleRiveinstances. - A potential feature request: Could
rive-react-nativesupport preloading or caching.rivfiles (e.g., aRive.preloadResourceAPI) to avoid redundant loading in list scenarios?
Thank you for your help in addressing this performance issue!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the provided ListItem and FlashList reproduction using rive-react-native 7.2.0, focusing on initialization of multiple Rive instances from excited_button.riv. Reproduce with 10 or more items, then investigate whether resource loading can be reused while preserving each instance's Level and Press state; done means smooth loading and scrolling without significant freezes.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react-native, typescript
- Domain
- mobile, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100