react-native-reels-list
is a customizable React Native component designed to provide an intagram/tiktok like optimized video list experience. It offers a variety of features and options to ensure smooth and efficient video playback in your React Native applications.
- Optimized video list for smooth performance
- Customizable video height
- Tap to mute functionality
- Hold to pause functionality
- Seekbar support
- Loading indicator
- Custom overlay components
- Playback status updates
Install the package via npm:
npm install react-native-reels-list
or via yarn:
yarn add react-native-reels-list
Note: This package uses expo-av
for video playback, expo-av is required to be installed in your project. Follow these installation instructions..
Here's an example of how to use the ReelsList
component in your React Native application:
import { useCallback, useContext } from "react";
import { VIEWPORT_HEIGHT } from "@/constants";
import { useBottomTabBarHeight } from "@react-navigation/bottom-tabs";
import ReelsList, { VideoItemType } from "react-native-reels-list";
import { MuteContext } from "@/context";
import { AVPlaybackStatus } from "expo-av";
const videos = [
{ key: '1', uri: 'https://example.com/video1.mp4', thumbnail: 'https://example.com/thumbnail1.jpg', ...otherProperties},
{ key: '2', uri: 'https://example.com/video2.mp4', thumbnail: 'https://example.com/thumbnail4.jpg', ...otherProperties},
// Add more videos as needed
];
const App = () => {
const tabBarHeight = useBottomTabBarHeight();
const { isMuted, handleMuteToggle } = useContext(MuteContext);
const [currentVideoIndex, setCurrentVideoIndex] = useState(0);
const [status, setStatus] = useState<AVPlaybackStatus | null>(null);
const videoHeight = VIEWPORT_HEIGHT - tabBarHeight;
const onViewableItemsChanged = useCallback(
(info: {
viewableItems: ViewToken<VideoItemType>[];
changed: ViewToken<VideoItemType>[];
}) => {
// Update the current video index when the viewable items change
setCurrentVideoIndex(
(prev) => info.changed.find((item) => item.isViewable)?.index ?? prev
);
// If required, add your custom logic here
},
[]
);
const handleGetItemLayout = useCallback(
(data: ArrayLike<VideoItemType> | null | undefined, index: number) => {
return {
length: videoHeight,
offset: videoHeight * index,
index,
};
},
[videoHeight]
);
const overlayComponent = useCallback(
({ item }: { item: VideoItemType, index:number }) => (
// Custom overlay component for each video item. Add your custom UI with position: 'absolute' here.
<View style={styles.overlay}>
<Link href={`/profile/${item.username}`} asChild>
<Pressable>
<Text>@{item.username}</Text>
</Pressable>
</Link>
</View>
),
[]
);
return (
<ReelsList
videoHeight={videoHeight}
currentVideoIndex={currentVideoIndex}
handleGetItemLayout={handleGetItemLayout}
onViewableItemsChanged={onViewableItemsChanged}
videos={videos}
isMuted={isMuted}
handleMuteToggle={handleMuteToggle}
showSeekbar={true}
showLoadingIndicator={true}
holdToPause={true}
overlayComponent={overlayComponent}
onCurrentPlaybackStatusUpdate={(status) => setStatus(status)}
refreshing={refreshing}
onRefresh={() => {
// Refresh the video list
}}
onEndReached={() => {
// Fetch more videos
}}
/>
);
};
export default FollowingTopTab;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
overlay:{
position: "absolute",
bottom: 40,
left: 8,
zIndex: 2,
}
});
export default App;
The ReelsList
component accepts the following props:
Prop | Type | Description | Default | Required |
---|---|---|---|---|
currentVideoIndex |
number | The index of the current video being played. | - | Yes |
handleGetItemLayout |
function | Function to get the layout of each item in the list. | - | Yes |
onViewableItemsChanged |
function | Callback function when viewable items change. | - | Yes |
videos |
Array<{ key: string, uri: string, thumbnail: string, ...otherProperties }> | Array of video items to be displayed in the list. | - | Yes |
videoHeight |
number | Height of each video in the list. | - | Yes |
isMuted |
boolean | Flag to mute/unmute videos. | false |
No |
handleMuteToggle |
function | Callback function to handle mute toggle. | - | No |
showSeekbar |
boolean | Flag to show/hide the seekbar. | false |
No |
showLoadingIndicator |
boolean | Flag to show/hide the loading indicator. | false |
No |
useNativeControls |
boolean | Flag to use native video controls. | false |
No |
holdToPause |
boolean | Flag to enable hold-to-pause functionality. | false |
No |
bottomOffset |
number | Offset from the bottom of the screen for the default seekbar and buffering indicator. | 0 |
No |
overlayComponent |
({ item, index }) => ReactNode | Function to render a custom overlay component for each video. | - | No |
onCurrentPlaybackStatusUpdate |
(status: AVPlaybackStatus) => void | A function to be called regularly with the AVPlaybackStatus of the currently playing video. Helps in tracking the playback status of the video for custom UI updates. | - | No |
Additionally, the component accepts all other FlatList props for added customizations.
Device | Max CPU Usage* | Idle CPU Usage | Avg. RAM Usage | Initial Load Time (Lazy Loading On) | Initial Load Time (Lazy Loading Off) |
---|---|---|---|---|---|
Two Video Lists (Two Top Tabs) | |||||
Samsung Galaxy A22 (6 GB RAM) | 70% | 13% | 650 MB | 1-2 Seconds | 18 Seconds |
Samsung Galaxy S22 Ultra (12 GB RAM) | 37% | 10% | 770 MB | 1-2 Seconds | 13 Seconds |
Samsung Galaxy A21s (4 GB RAM) | 75% | 18% | 698 MB | 4-5 Seconds | 30-40 Seconds |
One Video List (Single Top Tab) | |||||
Samsung Galaxy A22 (6 GB RAM) | 48% | 12% | 515 MB | 1-2 Seconds | - |
Samsung Galaxy S22 Ultra (12 GB RAM) | 32% | 10% | 635 MB | 1-2 Seconds | - |
Samsung Galaxy A21s (4 GB RAM) | 71% | 16% | 532 MB | 4-5 Seconds | - |
*Note: The maximum CPU usage values represent occasional spikes and should not be a cause for concern.
- If you are using multiple simultaneously running video lists, load the lists lazily for improved performance.
- On lower-end devices, if you encounter
java.lang.OutOfMemoryError
, setandroid:largeHeap="true"
in the Android manifest.
Contributions are welcome! Please open an issue or submit a pull request for any improvements or bug fixes.
Developed by Simranjit Singh.
Special thanks to all the contributors and the React Native community for their support and inspiration.