Prompt
Build a user directory screen with a FlatList. Requirements:
- Show a list of 20 users (name, email, avatar)
- Search bar filters by name (case-insensitive)
- Loading state while "fetching"
- Show "X results of Y users" header
Solution
This is the canonical "fetch + filter + list" screen, and the shipping concern it exercises is state shape: the only client state is the search string and the loading flag. The filtered list is derived in render — MOCK_USERS.filter(...) — never stored. One source of truth means there is nothing to keep in sync.
Mechanics worth defending:
- Controlled TextInput (
value+onChangeText): the search string lives in React state, so the header count, the filter, and the input can never disagree. - FlatList, not map-in-ScrollView: FlatList virtualizes — it mounts only a window of rows around the viewport and replaces the rest with correctly-sized blank space.
keyExtractorreturning the stableidis the identity contract that lets that window slide without remounting rows. - Loading as an early return keeps the happy-path JSX flat instead of nesting ternaries.
- The effect returns
clearTimeout— every subscription or timer an effect creates, its cleanup destroys.
Trade-off: filtering on every render is fine for 20 items; past a few hundred you wrap it in useMemo keyed on search — you memoize the derivation, you still don't store it.
Red flag: mirroring the filtered array into state with a useEffect that watches search. That's two renders per keystroke, a stale-sync bug waiting to happen, and the classic junior tell of "state for things that are computable."
Say it: "Search text is the only state — the filtered list is derived in render, and I'd memoize it before I'd ever store it."