perf(ui): use select API in RelationshipProvider to speed up load times in RelationshipCell (#13832)
### What? Optimize the `RelationshipProvider` to only select the `useAsTitle` field when fetching documents via the REST API. This reduces payload size and speeds up loading of the related document title in the`RelationshipCell` in the table view. ### Why? Previously, when a document had a relationship field, the full document data was requested in the table view, even though the relationship cell only shows the title in the UI. On large collections, this caused unnecessary overhead and slower UI performance. ### How? Applies a select to the REST API request made in the `RelationshipProvider`, limiting the responses to the `useAsTitle` field only. ### Notes - I’m not entirely sure whether this introduces a breaking change. If it does, could you suggest a way to make this behavior opt-in? - For upload enabled collections, the full document must be requested, because the relationship cell needs access to fields like `mimeType`, `thumbailURL` etc. - I hope we can find a way to get this merged. In the Payload projects I work on, this change has significantly improved list view performance. Similar to #13228
This commit is contained in:
@@ -16,6 +16,7 @@ import { RenderServerComponent } from '@payloadcms/ui/elements/RenderServerCompo
|
||||
import { getColumns, renderFilters, renderTable, upsertPreferences } from '@payloadcms/ui/rsc'
|
||||
import { notFound } from 'next/navigation.js'
|
||||
import {
|
||||
appendUploadSelectFields,
|
||||
combineWhereConstraints,
|
||||
formatAdminURL,
|
||||
isNumber,
|
||||
@@ -26,7 +27,6 @@ import {
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import { getDocumentPermissions } from '../Document/getDocumentPermissions.js'
|
||||
import { appendUploadSelectFields } from './appendUploadSelectFields.js'
|
||||
import { handleGroupBy } from './handleGroupBy.js'
|
||||
import { renderListViewSlots } from './renderListViewSlots.js'
|
||||
import { resolveAllFilterOptions } from './resolveAllFilterOptions.js'
|
||||
|
||||
@@ -58,6 +58,7 @@ export { validOperators, validOperatorSet } from '../types/constants.js'
|
||||
export { formatFilesize } from '../uploads/formatFilesize.js'
|
||||
|
||||
export { isImage } from '../uploads/isImage.js'
|
||||
export { appendUploadSelectFields } from '../utilities/appendUploadSelectFields.js'
|
||||
export { combineWhereConstraints } from '../utilities/combineWhereConstraints.js'
|
||||
|
||||
export {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { SanitizedCollectionConfig, SelectType } from 'payload'
|
||||
import type { ClientCollectionConfig, SanitizedCollectionConfig, SelectType } from '../index.js'
|
||||
|
||||
/**
|
||||
* Mutates the incoming select object to append fields required for upload thumbnails
|
||||
@@ -9,7 +9,7 @@ export const appendUploadSelectFields = ({
|
||||
collectionConfig,
|
||||
select,
|
||||
}: {
|
||||
collectionConfig: SanitizedCollectionConfig
|
||||
collectionConfig: ClientCollectionConfig | SanitizedCollectionConfig
|
||||
select: SelectType
|
||||
}) => {
|
||||
if (!collectionConfig.upload || !select) {
|
||||
@@ -1,6 +1,8 @@
|
||||
'use client'
|
||||
import type { TypeWithID } from 'payload'
|
||||
import type { SelectType, TypeWithID } from 'payload'
|
||||
|
||||
import { appendUploadSelectFields } from 'payload/shared'
|
||||
import * as qs from 'qs-esm'
|
||||
import React, { createContext, use, useCallback, useEffect, useReducer, useRef } from 'react'
|
||||
|
||||
import { useDebounce } from '../../../hooks/useDebounce.js'
|
||||
@@ -38,6 +40,7 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod
|
||||
|
||||
const {
|
||||
config: {
|
||||
collections,
|
||||
routes: { api },
|
||||
serverURL,
|
||||
},
|
||||
@@ -62,20 +65,29 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod
|
||||
const url = `${serverURL}${api}/${slug}`
|
||||
|
||||
const params = new URLSearchParams()
|
||||
const select: SelectType = {}
|
||||
|
||||
params.append('depth', '0')
|
||||
params.append('limit', '250')
|
||||
|
||||
const collection = collections.find((c) => c.slug === slug)
|
||||
if (collection.admin.enableListViewSelectAPI) {
|
||||
const fieldToSelect = collection.admin.useAsTitle ?? 'id'
|
||||
select[fieldToSelect] = true
|
||||
|
||||
if (collection.upload) {
|
||||
appendUploadSelectFields({ collectionConfig: collection, select })
|
||||
}
|
||||
}
|
||||
|
||||
if (locale) {
|
||||
params.append('locale', locale)
|
||||
}
|
||||
|
||||
if (idsToLoad && idsToLoad.length > 0) {
|
||||
const idsToString = idsToLoad.map((id) => String(id))
|
||||
params.append('where[id][in]', idsToString.join(','))
|
||||
}
|
||||
const idsToString = idsToLoad.map((id) => String(id))
|
||||
params.append('where[id][in]', idsToString.join(','))
|
||||
|
||||
const query = `?${params.toString()}`
|
||||
const query = `?${params.toString()}&${qs.stringify({ select })}`
|
||||
|
||||
const result = await fetch(`${url}${query}`, {
|
||||
credentials: 'include',
|
||||
@@ -100,7 +112,7 @@ export const RelationshipProvider: React.FC<{ readonly children?: React.ReactNod
|
||||
}
|
||||
})
|
||||
},
|
||||
[debouncedDocuments, serverURL, api, i18n, locale],
|
||||
[debouncedDocuments, serverURL, api, i18n, locale, collections],
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user