Async Posts List
Difficulty: Advanced
Problem Statementβ
Fetch posts on mount, show loading, render list, support filter action, handle failures gracefully.
Live Demoβ
Try the running app below β this is the target behavior for the challenge.
Async Posts List β Live Demo
Loadingβ¦
What Interviewers Expectβ
- Loading/error/success branches.
- Effect cleanup with mounted flag or abort.
- Test-friendly selectors (
data-testid).
Step-by-Step Implementationβ
Step 1 β Async effectβ
Fetch on mount and guard setState after unmount.
useEffect(() => { let mounted = true; ... return () => { mounted = false; }; }, []);
Step 2 β Loading UIβ
Render loading state until data arrives.
if (!posts) return <p>Loadingβ¦</p>;
Step 3 β Filter actionβ
Support user action to slice visible posts.
const visible = filtered ? posts.slice(0, 2) : posts;
Complete Implementationβ
Copy-paste ready single-file solution. Use this as your reference after attempting the challenge yourself, or paste it into CodeSandbox / StackBlitz to run locally.
App.jsx
import React, {useEffect, useState} from 'react';
const MOCK_POSTS = [
{id: 1, title: 'React state basics'},
{id: 2, title: 'Machine coding tips'},
{id: 3, title: 'Testing async UI'},
{id: 4, title: 'Transfer list patterns'},
];
export default function App() {
const [posts, setPosts] = useState(null);
const [error, setError] = useState('');
const [filtered, setFiltered] = useState(false);
useEffect(() => {
let mounted = true;
const timer = setTimeout(() => {
if (mounted) setPosts(MOCK_POSTS);
}, 700);
return () => {
mounted = false;
clearTimeout(timer);
};
}, []);
if (error) return <p>{error}</p>;
if (!posts) return <p>Loadingβ¦</p>;
const visible = filtered ? posts.slice(0, 2) : posts;
return (
<div>
<button type="button" onClick={() => setFiltered(true)}>
Filter first 2
</button>
<ul data-testid="list">
{visible.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
</div>
);
}
Final Checklistβ
- UI works for primary flow
- Edge cases handled (empty/disabled/loading where relevant)
- State updates are immutable
- Components are readable and reasonably split
- You can explain trade-offs out loud in an interview
Next Challengeβ
Continue to the next item in the sidebar when you're comfortable implementing this from scratch in 30β45 minutes.