Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem using rive with flatlist #292

Open
hyochan opened this issue Feb 25, 2025 · 0 comments
Open

Problem using rive with flatlist #292

hyochan opened this issue Feb 25, 2025 · 0 comments

Comments

@hyochan
Copy link

hyochan commented Feb 25, 2025

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

sumone.mp4

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant