Loading is not “No results”
No data yet means unknown, not empty. Show pending until it answers.
Guillermo Rauch@rauchgClassic. It’s not “No results” it’s “we don’t have results yet, therefore we don’t know” aka should render a loading spinner or the previous screen should suspend until information is obtained. Instead, this flashes and confuses the user.
He was quoting a post about mistaking error states for empty states.
1 · Filter while it fetches
Click a status filter and watch both lists.
Empty while fetchingBad
False “No results”
0Keeps last resultsGood
False “No results”
0const { data, error, isPending, isFetching, refetch } = useQuery({
queryKey: ["deployments", filter],
queryFn: () => getDeployments(filter),
placeholderData: keepPreviousData, // old rows stay while the new filter loads
});
if (isPending) return <ListSkeleton />; // unknown: first load
if (error) return <ErrorState onRetry={refetch} />; // failed is not empty
if (data.length === 0) return <Empty filter={filter} />; // the server said so
return <List rows={data} aria-busy={isFetching} dimmed={isFetching} />;
2 · Loading, empty and error
Pick what the server returns, then load orders.
Server returns
One state for allBad
Three statesGood
Why it matters, pros and cons
Why it matters
An empty state is a claim: there is nothing. Before the server answers you can't make it, so it flashes and misleads.
Pros
- No flash of “No results” on every filter change.
- Nobody acts on a false empty, like creating a duplicate.
- Failures get a retry instead of a shrug.
Cons
- Three states to design per list, not one.
- Dimmed stale rows need a clear pending cue.
- On very slow fetches, swap stale rows for a skeleton.