rive-app / rive-app/rive-react-native

Problem using rive with flatlist

Open
#292 0 comments 5 reactions 0 assignees View on GitHub

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 .riv file 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 Rive instance should maintain its independent state (e.g., Level value) 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 .riv file (excited_button.riv) across all list items, but each item needs its own animation state based on an excitedCount value mapped to a Level input.
  • Even with FlashList's initialNumToRender set to 5, the initial load is slow, and scrolling introduces noticeable bottlenecks as more Rive components enter the viewport.
  • I’ve tried delaying the setInputState call with setTimeout and InteractionManager.runAfterInteractions, but the performance issue persists, likely due to the overhead of initializing multiple Rive instances.
  • A potential feature request: Could rive-react-native support preloading or caching .riv files (e.g., a Rive.preloadResource API) to avoid redundant loading in list scenarios?

Thank you for your help in addressing this performance issue!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.