3.6 KiB
3.6 KiB
| title | aliases | tags | sources | created | updated | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| React Query — enabled: !!value Silent Skip on Empty String |
|
|
|
2026-04-30 | 2026-04-30 |
React Query — enabled: !!value Silent Skip on Empty String
When a React Query hook uses enabled: !!someId as a condition to fire the request, passing an empty string "" as someId silently disables the query — !!"" is false. The query never fires, the loading state resolves immediately with undefined data, and the UI shows nothing without any error or console warning.
Key Points
!!""isfalse— empty string is falsy in JavaScript; React Query treats it as "disabled"- Symptom: component renders, no network request is made, data is
undefined— looks like an API error but there is no request at all - Diagnosis: in React Query DevTools or browser network tab — if there's no request for a query that should have fired, check
enabledcondition for falsy values - Fix option A: use a separate hook or endpoint that doesn't require the ID (e.g.,
GET /clients/all-projectsthat returns all projects without a client filter) - Fix option B: use
enabled: someId !== null && someId !== undefinedinstead ofenabled: !!someIdto allow empty-string IDs
Details
The Failure Pattern
// useProjects hook — requires clientId
const { data: projects } = useQuery(
["projects", clientId],
() => fetchProjects(clientId),
{ enabled: !!clientId } // ← silently disabled when clientId === ""
);
// In a form where the user hasn't selected a client yet:
const [clientId, setClientId] = useState(""); // empty string default
// → query never fires, projects is undefined, dropdown is empty
Fix A: Separate "All Projects" Endpoint
When the UI needs ALL projects regardless of client selection, create a separate endpoint and hook that doesn't require a clientId:
// New hook — no clientId required
export function useAllProjects() {
return useQuery(["projects", "all"], fetchAllProjects); // always enabled
}
// New backend endpoint
// GET /clients/all-projects → returns all projects user has access to
This avoids changing the enabled logic and makes the "fetch all" intent explicit.
Fix B: Explicit Null Check
When the ID is legitimately optional but not always empty string:
const { data: projects } = useQuery(
["projects", clientId],
() => fetchProjects(clientId),
{ enabled: clientId !== null && clientId !== undefined }
// now "" (empty string) is allowed and the query fires
);
Common Falsy Values to Watch For in enabled
| Value | !!value |
Often means |
|---|---|---|
"" |
false |
Default state, unselected dropdown |
0 |
false |
First item in a zero-indexed list |
null |
false |
Not yet loaded |
undefined |
false |
Not yet loaded |
"0" |
true (string!) |
String zero — may be surprising |
When in doubt, use enabled: value !== null && value !== undefined rather than enabled: !!value.
Related Concepts
- wiki/concepts/zustand-async-hydration — another silent timing bug in React where state isn't ready when components mount
- wiki/tech-patterns/react-vite-typescript — React patterns in Oliver projects
Sources
- daily/2026-04-30.md — Brief form: projects dropdown empty because
useProjects('')was disabled byenabled: !!clientId; fixed withuseAllProjects()hook +GET /clients/all-projectsendpoint