Lesson 3: News Feed — Phase 3: State Ownership & Data Fetching

1. Key Architectural Rule
🔑 “Fetch data as close as possible to where it’s needed, but NOT so low in the tree that it duplicates requests.”
PostCard → ❌ WRONG (Firing 50 HTTP requests for 50 posts)
FeedList → ✅ RIGHT (Fetching ONCE and passing props down)
FeedPage → ℹ️ LAYOUT ONLY (Keeps top-level container simple & decoupled)
2. 3a. Prop Drilling (Data Flow Down the Tree)

“Right, so once FeedList has the array of posts, it just loops through them and passes each individual post down to PostCard as a prop.
Now, inside PostCard, that post data needs to reach smaller children too — like PostHeader needs the author info, and ReactionBar needs the like count. So PostCard just passes the relevant slice of that data further down as props to its own children.
This pattern — passing data down through multiple layers just so a deeply nested component can use it — is called prop drilling. It’s totally fine for a shallow tree like this one, two or three levels deep, it’s simple and explicit.
Where it becomes a problem is if the tree gets much deeper, or if many unrelated components in different branches all need the same piece of data — then you’re threading the same prop through five or six components that don’t actually care about it themselves, just to hand it further down. At that point, I’d reach for something like Context, or a state management library, instead of prop drilling.
But for this feed structure specifically — FeedList to PostCard to ReactionBar — it’s only two levels deep, so plain prop drilling is the right call. I wouldn’t reach for Context here just because it’s ‘more advanced’; that would be over-engineering something simple.”
3. 3b. 4 Types of State (UI vs Server vs URL vs Persistent)

“No, actually I’d break state into a few different categories, because each one behaves differently and I’d manage them differently.
First, there’s Server State — this is data that actually lives on the backend, like the list of posts, comments, like counts. The frontend doesn’t own this data, it just fetches a copy of it and keeps it in sync. This is exactly what we just talked about with FeedList fetching posts.
Then there’s UI State — this is purely local, presentation-level stuff that has nothing to do with the server. Things like whether a modal is open, which tab is currently active, or whether a ‘like’ button is mid-animation. This typically lives right inside the component that needs it, and doesn’t need to be shared globally.
Then there’s URL State — state that actually lives in the URL itself, like which feed tab you’re on, or a search filter. I like putting this in the URL when it makes sense, because it means the page is shareable and bookmarkable, and refreshing the page doesn’t lose that context.
And finally, there’s Persistent State — things like a draft post the user was writing, or saved preferences, that I’d want to survive even if they close the tab or refresh. That usually goes into something like local storage.
The reason I separate these is that mixing them up causes real problems — for example, if I treated server data like local UI state, I’d end up manually managing sync, refetching, and staleness myself, when a proper data-fetching layer is built to handle exactly that. So for the feed specifically: posts and comments are server state, whether the composer box is expanded is UI state, and the active feed tab — Following vs For You — I’d actually put in the URL.”
4. 3c. Like-State Ownership & Updating

🔑 “Update state at the level where it’s OWNED, not at the level where it’s DISPLAYED.”
ReactionBar → Displays the like count (does NOT own it)
FeedList → Owns the like count array (Single Source of Truth)
“So the like count is part of the post data, and we already said posts live as server state up at the FeedList level — that’s the single source of truth for all the post data. The ReactionBar, where the actual like button lives, is several levels deep — it doesn’t own that data itself, it just received it as a prop.
So when the user clicks like, I wouldn’t just update some local state inside ReactionBar in isolation — because if I did that, and the parent list re-renders or that post appears somewhere else on the page, the like count could get out of sync. Instead, the click needs to trigger an update at the source of truth — the posts array up in FeedList — and specifically just that one post inside it, not the whole list.
Practically, that means ReactionBar doesn’t hold its own like-count state — it just calls a function, something like onLike(postId), which gets passed down to it. That function actually updates the specific post’s like count in the shared posts data. Once that updates, React re-renders, and the new count flows back down through the same path — FeedList to PostCard to ReactionBar — automatically.
The key idea I’m applying here is: update state at the level where it’s owned, not at the level where it’s displayed. ReactionBar displays the like count, but it doesn’t own it — FeedList owns it. If I let a deeply nested component silently manage its own copy of shared data, I’d end up with inconsistent state across the app.
Now, one more thing worth mentioning — in practice, I wouldn’t want the user to wait for a server response before seeing the like count change, since that would feel sluggish. So I’d actually update the UI immediately, before the server even confirms it, and roll it back if the request fails. That’s a pattern called Optimistic UI, which I can go into more detail on if useful.”
🎯 5. Interview Technique Tip: “Contrast & Land”
💡 The “Contrast & Land” Pattern:
State the WRONG option first → Explain WHY it’s wrong → Land on the RIGHT answer.
Why interviewers love this: It proves architectural trade-off reasoning rather than memorization.
❓ Phase 3 Complete & Next Steps
Phase 3 Summary: Complete masterclass on Data Fetching Responsibility, Prop Drilling, 4 State Categories, and Like-State Mutability.
Next Phase: Phase 4: Frontend / Backend Boundary & API Contract Design