Skip to content

muxinc/Slop-Social

Repository files navigation

Slop Social 🎬

Slop Social Logo

A TikTok-style vertical video feed built with React Native and Expo, featuring buttery-smooth scrolling powered by Shopify's FlashList.

Demo

Tech Stack

  • React Native (0.81) with Expo (SDK 54)
  • @shopify/flash-list - High-performance list component
  • expo-video - Native video playback
  • Mux - Video streaming infrastructure
  • react-native-gesture-handler - Tap gestures for play/pause and double-tap to like
  • react-native-reanimated - Smooth animations

Why FlashList?

Traditional FlatList struggles with video feeds because it creates and destroys video components aggressively during scroll, leading to:

  • Janky scrolling
  • Delayed video loading
  • Memory spikes from multiple video instances

FlashList Performance Gains

FlashList uses cell recycling (similar to Android's RecyclerView and iOS's UICollectionView) which dramatically improves performance:

Metric FlatList FlashList
JS Thread FPS ~45-50 ~60 (stable)
Blank cells during fast scroll Frequent Rare
Memory usage Higher (no recycling) Lower (cell reuse)

Key Optimizations Used

<FlashList
  data={videos}
  renderItem={renderItem}
  // Pre-calculate item sizes for instant layout
  overrideItemLayout={(layout, _item, index) => {
    layout.size = SCREEN_HEIGHT;
    layout.offset = SCREEN_HEIGHT * index;
  }}
  // Render items within 3 screens for smooth scroll
  drawDistance={SCREEN_HEIGHT * 3}
  // Single item type = optimal recycling pool
  getItemType={() => "video"}
  // Full-screen snapping
  pagingEnabled
  snapToInterval={SCREEN_HEIGHT}
  decelerationRate="fast"
/>

Smart Video Preloading

The feed implements directional preloading to minimize buffering:

const MAX_PRELOAD_DISTANCE = 5;

// Preload 5 videos ahead in scroll direction
const shouldPreloadAhead = isAhead && Math.abs(distanceFromActive) <= MAX_PRELOAD_DISTANCE;
// Keep 1 video behind ready for quick back-scroll
const shouldPreloadBehind = !isAhead && Math.abs(distanceFromActive) === 1;

Videos not in the preload window have their source set to null, freeing up memory while maintaining the recycled view structure.

Getting Started

# Install dependencies
bun install

# Start the dev server
npx expo start

# Run on iOS
npx expo run:ios

# Run on Android
npx expo run:android

Project Structure

├── app/                    # Expo Router pages
│   ├── (tabs)/            # Tab navigation
│   │   ├── index.tsx      # Home feed
│   │   ├── discover.tsx   # Discover page
│   │   ├── create.tsx     # Create video
│   │   ├── inbox.tsx      # Notifications
│   │   └── profile.tsx    # User profile
├── components/
│   └── video-feed/
│       ├── video-feed.tsx # FlashList implementation
│       ├── video-item.tsx # Individual video player
│       └── video-overlay.tsx # UI overlay (likes, comments)
├── hooks/
│   ├── use-videos.ts      # Video data fetching
│   ├── use-likes.ts       # Like state management
│   └── use-video-playback.ts # Play/pause logic
└── types/
    └── video.ts           # TypeScript definitions

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published