fix: remove NO_ID_FIELD sentinel from data hooks when idField is not provided#738
fix: remove NO_ID_FIELD sentinel from data hooks when idField is not provided#738tyler-reitz wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Code Review
This pull request updates the idField initialization logic in src/database.tsx and src/firestore.tsx to use undefined instead of a string literal, and updates the observableId generation to use the nullish coalescing operator for better readability. The reviewer suggests further simplifying the idField assignment by removing redundant ternary operators, as the checkIdField function already handles undefined inputs appropriately.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| export function useDatabaseObjectData<T>(ref: DatabaseReference, options?: ReactFireOptions<T>): ObservableStatus<T> { | ||
| const idField = options ? checkIdField(options) : 'NO_ID_FIELD'; | ||
| const observableId = `database:objectVal:${ref.toString()}:idField=${idField}`; | ||
| const idField = options ? checkIdField(options) : undefined; |
There was a problem hiding this comment.
This ternary expression is redundant. The checkIdField function already handles cases where options is undefined by returning undefined. You can simplify this to a direct call to checkIdField(options).
| const idField = options ? checkIdField(options) : undefined; | |
| const idField = checkIdField(options); |
There was a problem hiding this comment.
Declining: the ternary guard at the call site is intentional. checkIdField and checkOptions are typed to expect a real ReactFireOptions object, and the hooks handle the no-options case before calling them. Widening the signatures to accept undefined would require options: ReactFireOptions | undefined since field follows as a required parameter, which isn't a meaningful improvement. The current shape keeps the function signatures strict.
| ): ObservableStatus<T[] | null> { | ||
| const idField = options ? checkIdField(options) : 'NO_ID_FIELD'; | ||
| const observableId = `database:listVal:${getUniqueIdForDatabaseQuery(ref)}:idField=${idField}`; | ||
| const idField = options ? checkIdField(options) : undefined; |
There was a problem hiding this comment.
This ternary expression is redundant. The checkIdField function already handles cases where options is undefined by returning undefined. You can simplify this to a direct call to checkIdField(options).
| const idField = options ? checkIdField(options) : undefined; | |
| const idField = checkIdField(options); |
There was a problem hiding this comment.
Declining: the ternary guard at the call site is intentional. checkIdField and checkOptions are typed to expect a real ReactFireOptions object, and the hooks handle the no-options case before calling them. Widening the signatures to accept undefined would require options: ReactFireOptions | undefined since field follows as a required parameter, which isn't a meaningful improvement. The current shape keeps the function signatures strict.
| */ | ||
| export function useFirestoreDocData<T = unknown>(ref: DocumentReference<T>, options?: ReactFireOptions<T>): ObservableStatus<T | undefined> { | ||
| const idField = options ? checkIdField(options) : 'NO_ID_FIELD'; | ||
| const idField = options ? checkIdField(options) : undefined; |
There was a problem hiding this comment.
This ternary expression is redundant. The checkIdField function already handles cases where options is undefined by returning undefined. You can simplify this to a direct call to checkIdField(options).
| const idField = options ? checkIdField(options) : undefined; | |
| const idField = checkIdField(options); |
There was a problem hiding this comment.
Declining: the ternary guard at the call site is intentional. checkIdField and checkOptions are typed to expect a real ReactFireOptions object, and the hooks handle the no-options case before calling them. Widening the signatures to accept undefined would require options: ReactFireOptions | undefined since field follows as a required parameter, which isn't a meaningful improvement. The current shape keeps the function signatures strict.
| */ | ||
| export function useFirestoreDocDataOnce<T = unknown>(ref: DocumentReference<T>, options?: ReactFireOptions<T>): ObservableStatus<T | undefined> { | ||
| const idField = options ? checkIdField(options) : 'NO_ID_FIELD'; | ||
| const idField = options ? checkIdField(options) : undefined; |
There was a problem hiding this comment.
This ternary expression is redundant. The checkIdField function already handles cases where options is undefined by returning undefined. You can simplify this to a direct call to checkIdField(options).
| const idField = options ? checkIdField(options) : undefined; | |
| const idField = checkIdField(options); |
There was a problem hiding this comment.
Declining: the ternary guard at the call site is intentional. checkIdField and checkOptions are typed to expect a real ReactFireOptions object, and the hooks handle the no-options case before calling them. Widening the signatures to accept undefined would require options: ReactFireOptions | undefined since field follows as a required parameter, which isn't a meaningful improvement. The current shape keeps the function signatures strict.
| export function useFirestoreCollectionData<T = DocumentData>(query: FirestoreQuery<T>, options?: ReactFireOptions<T[]>): ObservableStatus<T[]> { | ||
| const idField = options ? checkIdField(options) : 'NO_ID_FIELD'; | ||
| const observableId = `firestore:collectionData:${getUniqueIdForFirestoreQuery(query)}:idField=${idField}`; | ||
| const idField = options ? checkIdField(options) : undefined; |
There was a problem hiding this comment.
This ternary expression is redundant. The checkIdField function already handles cases where options is undefined by returning undefined. You can simplify this to a direct call to checkIdField(options).
| const idField = options ? checkIdField(options) : undefined; | |
| const idField = checkIdField(options); |
There was a problem hiding this comment.
Declining: the ternary guard at the call site is intentional. checkIdField and checkOptions are typed to expect a real ReactFireOptions object, and the hooks handle the no-options case before calling them. Widening the signatures to accept undefined would require options: ReactFireOptions | undefined since field follows as a required parameter, which isn't a meaningful improvement. The current shape keeps the function signatures strict.
Summary
useFirestoreDocData,useFirestoreDocDataOnce,useFirestoreCollectionData,useDatabaseObjectData, anduseDatabaseListDatawere passing the string'NO_ID_FIELD'to rxfire'skeyFieldoption when noidFieldwas provided by the caller"NO_ID_FIELD"(with the document ID as its value) to every returned document, polluting user data with an internal sentinelundefinedinstead, which rxfire already handles correctly by omitting the ID field entirely'none'as the no-idField sentinel (replacingundefined, which stringifies to"undefined"in template literals and would make cache keys ambiguous)Semver note
This is a bug fix:
NO_ID_FIELDappearing in returned data was never documented or intentional behavior. Code readingresult.NO_ID_FIELDwould break, but that code was relying on a bug. Semver call (patch vs. minor/major) left to Jeff, and this may ship alongside #735.Test plan
useFirestoreCollectionData,useFirestoreDocData, and database equivalentsFixes #295