sanity
Version:
Sanity is a real-time content infrastructure with a scalable, hosted backend featuring a Graph Oriented Query Language (GROQ), asset pipelines and fast edge caches
80 lines (72 loc) • 2.74 kB
text/typescript
import {type SanityDocument} from '@sanity/types'
import {useMemo} from 'react'
import {useObservable} from 'react-rx'
import {map, startWith} from 'rxjs/operators'
import {useDocumentStore} from '../store'
interface ReferringDocumentsState<Doc> {
isLoading: boolean
referringDocuments: Doc[]
}
/** @beta */
export type DocumentField = Exclude<keyof SanityDocument, number>
const INITIAL_STATE: ReferringDocumentsState<never> = {referringDocuments: [], isLoading: true}
const DEFAULT_FIELDS: DocumentField[] = ['_id', '_type']
/**
* @beta
* Subscribe to a live-updating list document referring to the document of the passed ID
* A new list of document will be emitted every time a document refers or no longer refers to the document of the given ID
*
* ## Gotcha
* The returned list of referring documents is not extensive, will only return the 101 first documents.
*
* ## Gotcha
* For every component that calls this hook, a new listener connection will be made to the backed.
*
* Make sure call this hook sparingly
* @param id - id of document to search for referring documents for
* @param fields - which fields to return for each document (defaults to _id and _type). Pass an empty array to return full documents
*/
export function useReferringDocuments<DocumentType extends SanityDocument>(
id: string,
fields: DocumentField[] = DEFAULT_FIELDS,
) {
const documentStore = useDocumentStore()
const projection = useMemo(() => {
return fields.length === 0 ? '' : fields.join(',')
}, [fields])
const observable = useMemo(
() =>
documentStore
.listenQuery(
`*[references($docId)] [0...101]${projection}`,
{docId: id},
{tag: 'use-referring-documents'},
)
.pipe(
map(
(docs: DocumentType[]): ReferringDocumentsState<DocumentType> => ({
referringDocuments: docs,
isLoading: false,
}),
),
startWith(INITIAL_STATE),
),
[documentStore, id, projection],
)
return useObservable(observable, INITIAL_STATE)
}
const EMPTY_FIELDS: never[] = []
/**
* Kept for backwards compat
* - useReferringDocuments(id) will select `{_id, _type}` from returned documents,
* - while this hook will return full documents
*
* Internal callers of this hook should migrate over to useReferringDocuments
* @deprecated - replaced by useReferringDocuments(id) but kept for backwards compatibility
* @internal
* @param id - id of document to search for referring documents for
*/
// eslint-disable-next-line camelcase
export function useLegacyReferringDocuments(id: string): ReferringDocumentsState<SanityDocument> {
return useReferringDocuments(id, EMPTY_FIELDS)
}