@sanity/sdk-react 2.3.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import {type DocumentHandle, getProjectionState, resolveProjection} from '@sanity/sdk'
2
2
  import {type SanityProjectionResult} from 'groq'
3
- import {useCallback, useSyncExternalStore} from 'react'
3
+ import {useCallback, useMemo, useSyncExternalStore} from 'react'
4
4
  import {distinctUntilChanged, EMPTY, Observable, startWith, switchMap} from 'rxjs'
5
5
 
6
6
  import {useSanityInstance} from '../context/useSanityInstance'
@@ -177,10 +177,21 @@ export function useDocumentProjection<TData extends object>({
177
177
  ...docHandle
178
178
  }: useDocumentProjectionOptions): useDocumentProjectionResults<TData> {
179
179
  const instance = useSanityInstance(docHandle)
180
- const stateSource = getProjectionState<TData>(instance, {...docHandle, projection})
180
+
181
+ // Normalize projection string to handle template literals with whitespace
182
+ // This ensures that the same projection content produces the same state source
183
+ // even if the string reference changes (e.g., from inline template literals)
184
+ const normalizedProjection = useMemo(() => projection.trim(), [projection])
185
+
186
+ // Memoize stateSource based on normalized projection and docHandle properties
187
+ // This prevents creating a new StateSource on every render when projection content is the same
188
+ const stateSource = useMemo(
189
+ () => getProjectionState<TData>(instance, {...docHandle, projection: normalizedProjection}),
190
+ [instance, normalizedProjection, docHandle],
191
+ )
181
192
 
182
193
  if (stateSource.getCurrent()?.data === null) {
183
- throw resolveProjection(instance, {...docHandle, projection})
194
+ throw resolveProjection(instance, {...docHandle, projection: normalizedProjection})
184
195
  }
185
196
 
186
197
  // Create subscribe function for useSyncExternalStore
@@ -52,6 +52,7 @@ describe('usePerspective', () => {
52
52
  _updatedAt: '2021-01-01T00:00:00Z',
53
53
  _rev: 'rev1',
54
54
  name: 'Test Release',
55
+ state: 'scheduled',
55
56
  metadata: {
56
57
  title: 'Test Release',
57
58
  releaseType: 'asap',
@@ -43,7 +43,7 @@ export const usePerspective: UsePerspective = createStateSourceHook({
43
43
  instance: SanityInstance,
44
44
  perspectiveHandle?: PerspectiveHandle,
45
45
  ) => StateSource<string | string[]>,
46
- shouldSuspend: (instance: SanityInstance, options?: PerspectiveHandle): boolean =>
46
+ shouldSuspend: (instance: SanityInstance, options: PerspectiveHandle): boolean =>
47
47
  getPerspectiveState(instance, options).getCurrent() === undefined,
48
48
  suspender: (instance: SanityInstance, _options?: PerspectiveHandle) =>
49
49
  firstValueFrom(getActiveReleasesState(instance).observable.pipe(filter(Boolean))),
@@ -62,7 +62,7 @@ export interface UsersResult {
62
62
  * <address>{user.profile.email}</address>
63
63
  * </figure>
64
64
  * ))}
65
- * {hasMore && <button onClick={loadMore}>{isPending ? 'Loading...' : 'Load More'</button>}
65
+ * {hasMore && <button onClick={loadMore}>{isPending ? 'Loading...' : 'Load More'}</button>}
66
66
  * </div>
67
67
  * )
68
68
  * ```