如何在Sanity Studio+Next.js中自定义预览模式并获取引用分类数据
解决Sanity Studio预览模式中获取引用分类数据的问题
问题核心是Sanity Studio默认只会返回文档中的引用ID(_ref),不会自动展开引用的关联文档,因此需要手动通过Sanity Client查询分类数据。
步骤1:引入并配置Sanity Client
在structure.ts中创建Studio可用的Sanity客户端,用于查询分类文档:
import { createClient } from '@sanity/client'; import type { SanityDocument } from 'sanity'; // 配置Studio客户端 const client = createClient({ projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID, dataset: process.env.NEXT_PUBLIC_SANITY_DATASET, useCdn: false, // 禁用CDN以获取最新草稿数据 apiVersion: '2024-01-01', // 使用当前最新API版本 });
步骤2:修正TypeScript接口定义
匹配实际数据结构,categories是引用数组而非单个对象:
interface Doc extends SanityDocument { slug: { current: string }; categories: Array<{ _ref: string; _type: string; _key: string }>; } // 分类文档的类型定义 interface Category { _id: string; title: string; }
步骤3:重写异步的预览URL生成函数
通过客户端查询引用的分类数据,同时处理异常和 fallback 情况:
async function getPreviewUrl(doc: Doc) { const baseUrl = process.env.NEXT_PUBLIC_VERCEL_URL || window.location.host; if (!doc?.slug?.current) { return `https://${baseUrl}`; } // 默认分类 fallback 值 let categoryTitle = 'uncategorized'; // 若存在分类引用,获取第一个分类的标题 if (doc.categories?.length > 0) { const categoryRef = doc.categories[0]._ref; try { const category = await client.getDocument<Category>(categoryRef); categoryTitle = category.title; } catch (err) { console.error('获取分类数据失败:', err); } } return `https://${baseUrl}/articles/${categoryTitle}/${doc.slug.current}`; }
步骤4:更新文档视图配置
Sanity Studio的Iframe视图支持返回Promise的url函数,直接传入异步生成逻辑即可:
export const defaultDocumentNode = (S, { schemaType }) => { switch (schemaType) { case `article`: return S.document().views([ S.view.form(), S.view.component(Iframe).options({ url: async (doc: Doc) => getPreviewUrl(doc) }) ]); default: return S.document().views([S.view.form()]); } };
注意事项
- 确保
.env文件中配置了正确的NEXT_PUBLIC_SANITY_PROJECT_ID和NEXT_PUBLIC_SANITY_DATASET环境变量。 - 如果数据集是私有的,需要在客户端配置中添加
token(可在Sanity管理后台生成)。 - 若文章关联多个分类,可根据需求调整逻辑(比如取第一个、拼接多个分类等)。
内容的提问来源于stack exchange,提问作者Toss
相关产品推荐
相关产品推荐

