Skip to content

Commit 954d7ae

Browse files
authored
docs: write Document Handle guide; fix errant Fragment in example (#373)
* docs: write Document Handle guide; fix errant Fragment in example * docs: fix grammar * docs: expand explanation * docs: fix typing * docs: update file names for sort ordering * docs: remove list of hooks in handles doc
1 parent 8950830 commit 954d7ae

File tree

6 files changed

+170
-6
lines changed

6 files changed

+170
-6
lines changed

packages/core/src/document/patchOperations.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ type SingleValuePath = Exclude<PathSegment, IndexTuple>[]
2020
* @category Types
2121
*/
2222
export interface DocumentHandle<TDocument extends SanityDocumentLike = SanityDocumentLike> {
23+
/** The Sanity document ID */
2324
_id: string
25+
/** The type of document, for example 'post' or 'author' */
2426
_type: TDocument['_type']
2527
resourceId?: DocumentResourceId
2628
}

packages/react/guides/MIGRATION.md renamed to packages/react/guides/0-Migration-Guide.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# Migration guide
1+
---
2+
title: Migration guide
3+
---
24

35
## Migrating to @sanity/sdk-react@0.0.0-rc.2
46

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
---
2+
title: Introducing Document Handles
3+
---
4+
5+
# Introducing Document Handles
6+
7+
Document Handles ({@link DocumentHandle see their type definition here}) are a new concept introduced by the Sanity App SDK, and are important to understand when working with many of the SDK’s React hooks. In this guide, we’ll describe what Document Handles are, why they’re useful, and how to work with them.
8+
9+
## What is a Document Handle?
10+
11+
In short, a Document Handle is a ‘stub’ of a document — a small piece of metadata, encoded in a JavaScript object, that acts as a reference to a complete document in your dataset(s).
12+
13+
It looks like this:
14+
15+
```JavaScript
16+
const myDocumentHandle = {
17+
_id: 'my-document-id',
18+
_type: 'article'
19+
}
20+
```
21+
22+
A Document Handle may also contain a resource ID; in that case, it would look like this:
23+
24+
```JavaScript
25+
const myDocumentHandle = {
26+
_id: 'my-document-id',
27+
_type: 'author',
28+
resourceId: `document:${projectId}.${dataset}:${documentId}`
29+
}
30+
```
31+
32+
Therefore, for a document in a given dataset that looks (in part) like this:
33+
34+
```JSON
35+
{
36+
"_id": "123456-abcdef",
37+
"_type": "book",
38+
"title": "Into the Cool",
39+
"publisher": "The University of Chicago Press",
40+
"pages": 378,
41+
"…": ""
42+
}
43+
```
44+
45+
…the corresponding Document Handle would look like this:
46+
47+
```JavaScript
48+
{
49+
_id: "123456-abcdef",
50+
_type: "book"
51+
}
52+
```
53+
54+
## Why are Document Handles used?
55+
56+
Hooks like {@link useDocuments} and {@link usePaginatedDocuments} can return potentially large numbers of documents matching your specified parameters. If these hooks were to return every matching document in its entirety, this could end up being a potentially performance heavy operation, which could thus slow down your application and result in a poor user experience. Additionally, you may not need each returned document in its entirety to begin with — perhaps, for example, you just want to render a document preview, or one or two arbitrary fields of a document, or to simply get a count of documents matching your parameters.
57+
58+
This is where the concept of Document Handles comes in. By returning a small amount of metadata for each document instead of unfurling every returned document, hooks like {@link useDocuments} can respond as fast as possible, allowing your application to remain snappy.
59+
60+
Of course, unless you’re just looking to get a count of documents matching the parameters you pass to these hooks, Document Handles aren't incredibly useful on their own. This is by design — they’re only meant to serve as references to documents which can then be consumed by more specialized hooks, such as {@link useProjection}, {@link useDocument}, and many more hooks provided by the SDK. These specialized hooks are designed to consume document handles and emit only the document content you request, which also delivers huge performance benefits. Other hooks, such as {@link useDocumentEvent} and {@link useDocumentPermissions} have no need to know the contents of a document — instead, they use the provided Document Handle to reference a document and retrieve information pertaining to that document.
61+
62+
In short, Document Handles promote deferring the retrieval of document contents until such time as those contents are actually needed by your application.
63+
64+
## Using your own Document Handles
65+
66+
You’re not limited to using Document Handles returned by hooks like {@link useDocuments} — if it suits your use case (for example: if you know the document ID and type of the document you want to reference), you can certainly write and use your own Document Handles.
67+
68+
For example:
69+
70+
```tsx
71+
import {useDocumentSyncStatus, type DocumentHandle} from '@sanity/sdk-react'
72+
73+
const myDocumentHandle: DocumentHandle = {
74+
_id: 'my-document-id',
75+
_type: 'book',
76+
}
77+
78+
const documentSynced = useDocumentSyncStatus(myDocumentHandle)
79+
```
80+
81+
## A quick example
82+
83+
Let’s say you’d like to get all of the documents of type `'author'` from a dataset. In your Sanity application, you could use the {@link useDocuments} hook to do that:
84+
85+
```tsx
86+
import {useDocuments} from '@sanity/sdk'
87+
88+
export function AuthorList() {
89+
const {data: authors} = useDocuments({filter: '_type: "author"'})
90+
}
91+
```
92+
93+
At this point, the `authors` variable contains an array of Document Handles, which, because we’re filtering for only the `author` content type, will look like this:
94+
95+
```tsx
96+
{ _id: 'the-document-id', _type: 'author' }
97+
```
98+
99+
With this information, we could render the number of authors in the dataset — for example:
100+
101+
```tsx
102+
import {useDocuments} from '@sanity/sdk'
103+
104+
export function AuthorList() {
105+
const {data: authors} = useDocuments({filter: '_type: "author"'})
106+
107+
return <p>There are currently {authors.length} authors in our dataset.</p>
108+
}
109+
```
110+
111+
If we wanted to instead render content from each of these documents — for example, the author’s name — we’d then need to pass each Document Handle to a different hook — for example, {@link useProjection}:
112+
113+
```tsx
114+
import {useProjection, type DocumentHandle} from '@sanity/sdk'
115+
116+
interface ProjectionResult {
117+
results: {
118+
name: string
119+
}
120+
}
121+
122+
// The AuthorDetails component will accept a Document Handle for its `document` prop
123+
export function AuthorDetails({document}: {document: DocumentHandle}) {
124+
const {results}: ProjectionResult = useProjection({
125+
document,
126+
projection: '{ name }',
127+
})
128+
129+
return <p>The author's name is {results.name}</p>
130+
}
131+
```
132+
133+
We can then use our `AuthorDetails` component with our previously created `AuthorList` component, and pass along the Document Handles to each instance of the `AuthorDetails` component:
134+
135+
```tsx
136+
import {useDocuments} from '@sanity/sdk'
137+
138+
import AuthorDetails from './AuthorDetails.tsx'
139+
140+
export function AuthorList() {
141+
const { data: authors } = useDocuments({ filter: '_type: "author"'})
142+
143+
return (
144+
<>
145+
<p>There are {authors.length} authors in our dataset! Here they are:</p>
146+
<ul>
147+
{authors.map(author => (
148+
<li key={author._id}>
149+
<AuthorDetails document={author} />
150+
</li>
151+
)}
152+
</ul>
153+
</>
154+
)
155+
}
156+
```
157+
158+
We’ve now both retrieved a list of Document Handles, and used each of them in a dedicated component with a hook that consumes Document Handles. No matter how many authors there are in our dataset, nor how many fields might exist on our author type, this will keep our application performing as fast as possible by separating the concerns of retrieving author type documents (or rather, Document Handles) and retrieving data from those documents.
159+
160+
```
161+
162+
```
File renamed without changes.
File renamed without changes.

packages/react/src/hooks/paginatedDocuments/usePaginatedDocuments.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,9 @@ export interface PaginatedDocumentsResponse {
150150
* <MyTableRowComponent key={doc._id} doc={doc} />
151151
* ))}
152152
* </table>
153-
* <>
154-
* {hasPreviousPage && <button onClick={previousPage}>Previous</button>}
155-
* {currentPage} / {totalPages}
156-
* {hasNextPage && <button onClick={nextPage}>Next</button>}
157-
* </>
153+
* {hasPreviousPage && <button onClick={previousPage}>Previous</button>}
154+
* {currentPage} / {totalPages}
155+
* {hasNextPage && <button onClick={nextPage}>Next</button>}
158156
* </>
159157
* )
160158
* ```

0 commit comments

Comments
 (0)