sanity-plugin-computed-field
Version:
Sanity plugin that computes a field's value based on other fields or relationships with its document or external data. In other words, this field memoizes a value in a document using GROQ to lookup and custom javascript to compute the value from those GRO
57 lines (52 loc) • 1.77 kB
text/typescript
import React from 'react'
import {useClient, useFormValue} from 'sanity'
import {ComputedQueryResult} from '../schema/types'
type ComputedDocumentResult = {
_id: string
[s: string]: unknown
}
export const useQueryReducer = <FieldDataType>({
reduceQueryResult,
documentQuerySelection,
handleValueChange,
value,
}: {
reduceQueryResult: (result: ComputedQueryResult) => FieldDataType | Promise<FieldDataType>
handleValueChange: (updatedValue: FieldDataType) => void
documentQuerySelection: string
value?: FieldDataType
}): {
handleRegenerateValue: () => void
isRegenerating: boolean
} => {
const [loading, setLoading] = React.useState(false)
const client = useClient()
const docId: string = useFormValue(['_id']) as string
const _type: string = useFormValue(['_type']) as string
const reducer = React.useCallback(
(queryResult: ComputedQueryResult) => reduceQueryResult(queryResult),
[reduceQueryResult],
)
const handleRegenerateValue = React.useCallback(async () => {
const query = `*[_type == '${_type}' && _id == '${docId}' || _id == '${docId.replace(
'drafts.',
'',
)}'] {
_id,
${documentQuerySelection}
}`
setLoading(true)
const items: ComputedDocumentResult[] = await client.fetch(query)
const draft = items.find(({_id}) => _id.includes('drafts'))
const published = items.find(({_id}) => !_id.includes('drafts')) as ComputedDocumentResult
const newValue = await Promise.resolve(reducer({draft, published}))
if (newValue !== value) {
handleValueChange(newValue)
}
setLoading(false)
}, [_type, docId, documentQuerySelection, client, reducer, value, handleValueChange])
return {
handleRegenerateValue,
isRegenerating: loading,
}
}