React Native Video Component Refreshing Excessively on Zustand State Updates Causing Performance Degradation and Crashes on Android

131 Views Asked by At

Issue

I am currently developing a social media-like mobile app using React Native. In this app, I'm utilizing two key components: FlashList from @shopify/flash-list for rendering posts and react-native-video for handling video playback. However, I've encountered a problematic behavior where the react-native-video component refreshes every time I update a state using Zustand. This constant refreshing issue not only causes a significant performance drop but also leads to crashes on Android devices.

Code Structure

Here's an overview of my code structure:

// Other imports...
import { FlashList } from '@shopify/flash-list'
// Other imports...

// Component
import SocialContents from '../../components/Recognition/Contents'
// Zustand Store
import useSocialWallStore from '../../store/useSocialWallStore'

const XXX = ({ props, route }) => {

  const { getSocialWallContent, socialWallContents } =
    useSocialWallStore((state) => state)

  const generateNewData = () => {
    // Generate new data...
  }

  // Other code...

  const SocialContentsMemo = React.memo(SocialContents)
  const wallData = socialWallContents?.contents.sort(
    (a, b) => Date.parse(b.dateCreatedUtc) - Date.parse(a.dateCreatedUtc),
  )
  
  return (
    <SafeAreaView style={{ flex: 1, backgroundColor: "white" }}>
      {/* Other codes here... */}
      <View
        style={{
          height: Dimensions.get("screen").height,
          width: Dimensions.get("screen").width,
        }}
      >
        <FlashList
          estimatedItemSize={
            // This is the total data...
          }
          onEndReached={() => generateNewData()}
          onEndReachedThreshold={0.1}
          scrollEventThrottle={50}
          keyboardShouldPersistTaps="handled"
          contentContainerStyle={{
            paddingHorizontal: 18,
            paddingBottom: 225,
            paddingTop: 0,
          }}
          data={wallData}
          keyExtractor={(_, index) => index.toString()}
          renderItem={({ item, index }) => (
            <View key={index}>
              <SocialContentsMemo data={item} onDelete={onDelete} />
            </View>
          )}
          ListFooterComponent={() =>
            socialWallContents?.loadingMore && (
              <View className="w-full items-center justify-center py-4">
                <ActivityIndicator color={'black'} size="large" />
              </View>
            )
          }
        />
      </View>
      {/* Other codes here... */}
    </SafeAreaView>
  );
}

export default XXX

Additionally, here's how I display the video within the SocialContents component:

{data?.mediaUrl && (
  <View className="relative w-full py-1">
    {['.mp4', '.webm', '.avi', '.mov', '.mkv', '.flv'].some(
      (format) => data.mediaUrl.endsWith(format),
    ) ? (
      <>
        <Video
          source={{ uri: data.mediaUrl }}
          style={{ width: '100%', height: 200 }}
          resizeMode="contain"
          controls={isBuffered}
          paused={true}
          onLoad={() => setIsBuffered(true)}
        />
        {!isBuffered && (
          <ActivityIndicator
            className="absolute left-[50%] top-[50%]"
            size="large"
          />
        )}
      </>
    ) : ['jpg', '.jpeg', '.png', '.gif'].some((format) =>
        data.mediaUrl.endsWith(format),
      ) ? (
        // For displaying images...
    ) : ['mp3', '.wav', '.ogg'].some((format) =>
        data.mediaUrl.endsWith(format),
      ) ? (
        // For handling audio...
    ) : null}
  </View>
)}

Version/Package:

"react-native-video": "^5.2.1",
"@shopify/flash-list": "^1.6.1",
"zustand": "^4.0.0",
"react-native": "0.69.4",
"react": "18.0.0",

If you have any questions or need further assistance with this issue, please feel free to ask.

1

There are 1 best solutions below

0
Mathew Agustin Bella On

I solved it using a callback

Solution:

  const memoizedRenderItem = useCallback(
    ({ item, index }) => (
      <View key={index}>
        <SocialContents data={item} onDelete={onDelete} />
      </View>
    ),
    [onDelete],
  )