Feed
Location: src/components/Feed.jsx
Overview
Feed is the central content display for CommonPlace. Unlike conventional social feeds, it enforces slow-feed pacing to prevent addictive scrolling patterns. Posts are divided into new (since the user last visit) and previous (before the last visit) groups, giving users a clear sense of completion rather than an endless stream.
The component supports three pacing modes (slow, normal, live) and a filter system that includes base filters (all posts, friends only) plus dynamic per-circle filters. Real-time subscriptions are only active in live mode.
Relevant Invariants
- Invariant #2: "Calm Is the Default State" -- Feed defaults to normal mode (1-hour refresh), with no urgency cues or auto-loading.
- Invariant #8: "Feed Is a View, Not a Goal" -- Posts are session-bounded, not ranked or scored.
- Invariant #12: "Slowness Is Baked In" -- Batched loading with explicit refresh and paced intervals.
- Invariant #13: "Absence Is First-Class" -- Empty feeds display a calm completion state, not a broken one.
Props
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
session | object | Yes | -- | Supabase auth session with user.id |
feedMode | string | Yes | -- | Current pacing mode: slow, normal, or live |
setFeedMode | function | Yes | -- | Callback to change the pacing mode |
showComposer | boolean | Yes | -- | Whether the inline CreatePost form is visible |
onCloseComposer | function | Yes | -- | Callback when user closes the inline composer |
Constants
| Constant | Value | Description |
|---|---|---|
PACING_INTERVALS.slow | 21600000 (6 hrs) | Minimum time between feed refreshes in slow mode |
PACING_INTERVALS.normal | 3600000 (1 hr) | Minimum time between feed refreshes in normal mode |
PACING_INTERVALS.live | 0 | No restriction; real-time subscription active |
PREVIOUS_POSTS_PAGE_SIZE | 20 | Number of previous posts loaded per page |
Key Behaviors
- Session Cutoff: Uses
user_feed_state.last_checked_atto divide posts into new vs. previous groups. - Pacing Gate: In slow/normal modes, the feed only re-fetches if enough time has elapsed since
last_checked_at. - Filter Persistence: The selected filter is stored in
localStorageunder the keyfeedFilter. - Circle Filters: Dynamically generated from the user circles via
useCircleshook, appearing alongside base filters. - Real-time: Only in
livemode, a Supabase channel subscription pushes new posts into the feed. - Stepped-back Friends: Uses
useSteppedBackto apply visual indicators for friends in a stepped-back state.
Usage
import Feed from '@/components/Feed';
function App({ session }) {
const [feedMode, setFeedMode] = useState('normal');
const [showComposer, setShowComposer] = useState(false);
return (
<Feed
session={session}
feedMode={feedMode}
setFeedMode={setFeedMode}
showComposer={showComposer}
onCloseComposer={() => setShowComposer(false)}
/>
);
}
Related
- Post -- Individual post rendering
- CreatePost -- Inline post creation form
- Header -- Feed mode selector lives here
Last updated: 2026-02-07