@fastcontents/react
v0.3.2
Published
React component for navigating through short-form content with efficient buffering and prefetching.
Readme
@fastcontents/react
React component for navigating through short-form content with efficient buffering and prefetching.
Installation
npm install @fastcontents/reactFeatures
- 🎯 Navigation-based: Display one content item at a time with prev/next controls
- 👆 Swipe Gestures: Built-in support for TikTok-style vertical or Instagram-style horizontal swiping
- 🚀 Smart buffering: Automatically prefetches content ahead of user navigation
- ⚡ Efficient loading: Loads content in small batches to minimize initial load time
- 🎨 Fully customizable: Bring your own UI for content and navigation controls
- 📱 Mobile-friendly: Optimized for touch interactions and mobile devices
Basic Usage
import { FastContent } from '@fastcontents/react';
interface Post {
id: number;
title: string;
content: string;
}
function App() {
const fetchCallback = async ({ offset, limit }) => {
const response = await fetch(`/api/posts?offset=${offset}&limit=${limit}`);
const data = await response.json();
return {
items: data.posts,
hasMore: data.hasMore,
};
};
return (
<FastContent
fetchCallback={fetchCallback}
renderer={({ content, index }) => (
<div>
<h2>{content.title}</h2>
<p>{content.content}</p>
</div>
)}
renderControls={({ hasPrev, hasNext, onPrev, onNext, isLoading }) => (
<div>
<button onClick={onPrev} disabled={!hasPrev || isLoading}>
Previous
</button>
<button onClick={onNext} disabled={!hasNext || isLoading}>
Next
</button>
</div>
)}
/>
);
}Swipe Support
Enable swipe gestures for a modern mobile experience.
Vertical Swipe (TikTok style)
<FastContent
fetchCallback={fetchVideos}
renderer={VideoPlayer}
enableSwipe={true}
orientation="vertical"
initialBatchSize={3}
/>Horizontal Swipe (Stories style)
<FastContent
fetchCallback={fetchStories}
renderer={StoryViewer}
enableSwipe={true}
orientation="horizontal"
/>API Reference
FastContent Props
fetchCallback (required)
type FetchCallback<T> = (params: { offset: number; limit: number }) => Promise<{
items: T[];
hasMore: boolean;
}>;Function to fetch content. Receives pagination parameters and returns items with a flag indicating if more content is available.
renderer (required)
type Renderer<T> = React.ComponentType<{
content: T;
index: number;
}>;Component to render each content item. Receives the current content and its global index.
renderControls (optional)
type RenderControls = (props: {
hasPrev: boolean;
hasNext: boolean;
onPrev: () => void;
onNext: () => void;
isLoading: boolean;
}) => React.ReactNode;Custom navigation controls. If not provided, you'll need to implement your own navigation UI or use swipe gestures.
initialBatchSize (optional)
- Type:
number - Default:
3
Number of items to fetch on initial load. Keep this small for faster initial rendering.
batchSize (optional)
- Type:
number - Default:
3
Number of items to fetch when loading more content.
fallback (optional)
- Type:
React.ReactNode - Default:
undefined
UI to show while the initial content is loading.
enableSwipe (optional)
- Type:
boolean - Default:
false
Enables touch swipe gestures for navigation.
orientation (optional)
- Type:
'horizontal' | 'vertical' - Default:
'horizontal'
Direction of swipe gestures.
swipeThreshold (optional)
- Type:
number - Default:
50
Distance in pixels the user must swipe to trigger navigation.
SwipeWrapper (optional)
- Type:
React.ComponentType<SwipeWrapperProps> - Default:
DefaultSwipeWrapper
Custom component to wrap the swipeable items. Use this to customize animations or layout during swipe.
Advanced Usage
Full-Screen Content with Keyboard Navigation
import { FastContent } from '@fastcontents/react';
import { useEffect } from 'react';
function VideoFeed() {
const fetchVideos = async ({ offset, limit }) => {
const res = await fetch(`/api/videos?offset=${offset}&limit=${limit}`);
return res.json();
};
const VideoPlayer = ({ content, index }) => (
<div style={{ height: '100vh', width: '100vw' }}>
<video src={content.url} controls autoPlay />
<h2>{content.title}</h2>
</div>
);
const NavigationControls = ({ hasPrev, hasNext, onPrev, onNext, isLoading }) => {
useEffect(() => {
const handleKeyDown = (e) => {
if (e.key === 'ArrowUp' && hasPrev) onPrev();
if (e.key === 'ArrowDown' && hasNext) onNext();
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
}, [hasPrev, hasNext, onPrev, onNext]);
return (
<div style={{ position: 'fixed', bottom: 20, left: '50%', transform: 'translateX(-50%)' }}>
<button onClick={onPrev} disabled={!hasPrev}>↑</button>
<button onClick={onNext} disabled={!hasNext}>↓</button>
</div>
);
};
return (
<FastContent
fetchCallback={fetchVideos}
renderer={VideoPlayer}
renderControls={NavigationControls}
initialBatchSize={5}
batchSize={5}
enableSwipe={true}
orientation="vertical"
/>
);
}Using the Hook Directly
For more control, use the useFastContent hook:
import { useFastContent } from '@fastcontents/react';
function CustomContentViewer() {
const {
currentItem,
currentIndex,
isLoading,
hasMore,
items,
goNext,
goPrev,
} = useFastContent({
fetchCallback: async ({ offset, limit }) => {
const res = await fetch(`/api/content?offset=${offset}&limit=${limit}`);
return res.json();
},
initialBatchSize: 3,
batchSize: 3,
scrollThreshold: 200, // Optional: for infinite scroll logic
});
if (!currentItem) {
return <div>Loading...</div>;
}
return (
<div>
{/* Custom UI Implementation */}
</div>
);
}Hook API
useFastContent<T>(config)
Returns an object with:
currentItem: T | undefined- The currently displayed itemcurrentIndex: number- Index of the current itemitems: T[]- All loaded itemsisLoading: boolean- Whether content is currently being fetchedisInitialized: boolean- Whether initial load is completehasMore: boolean- Whether more content is available from the servererror: Error | null- Any error that occurred during fetchinggoNext: () => Promise<void>- Navigate to the next itemgoPrev: () => void- Navigate to the previous itemloadMore: () => Promise<void>- Manually trigger loading more contentnextItem: T | undefined- The next item (for prefetching)prevItem: T | undefined- The previous item
Configuration Object
fetchCallback(required): Function to fetch data.initialBatchSize(optional): Items to load initially.batchSize(optional): Items to load per batch.scrollThreshold(optional): Threshold for triggering loadMore in scroll-based implementations.
Other Exports
The package also exports building blocks for custom swipe implementations:
useSwipe: Hook for handling touch events and swipe logic.SwipeItem: Component for wrapping individual swipe items.DefaultSwipeWrapper: The default container for swipeable content.SwipeOrientation: Type definition for 'horizontal' | 'vertical'.
Performance Tips
- Keep batch sizes small (3-5 items) for faster initial load
- Use the
fallbackprop to show loading UI during initial fetch - Prefetch media in your renderer when
nextItemis available - Memoize your renderer component to avoid unnecessary re-renders
- Use
enableSwipefor mobile-first experiences
Testing
Run tests:
pnpm testLicense
MIT
