Issue with updating preview in Next.js project using next-sanity package

46 replies
Last updated: Sep 10, 2021
Hi! Not sure if this is the right place. I’ve tried to add preview in sanity (using next-sanity) to my next project and it doesn’t seem to update. It looks like the preview prop is false when loading the iframe. Any idea how to solve this?
Aug 23, 2021, 9:14 AM
Hey (Removed Name)! This is the right place! What does your code look like?
Aug 23, 2021, 8:06 PM
[slug].js

import ErrorPage from 'next/error'
import { useRouter } from 'next/router'
import { groq } from 'next-sanity'

import { RenderSections } from '../components/RenderSections'
import { usePreviewSubscription } from '../lib/sanity'
import { getClient } from '../lib/sanity.server'

const PAGE_QUERY = groq`
*[_type == "page" && slug.current == $slug][0]{
    ...,
    content[]{
        ...,
        _type == "hero" => {
            ...,
            heroSlides[_type == "reference"] -> {
                ...,
            },
            "pageHeroSlides": *[_type == "page" && slug.current == $slug][0].content[_type == "hero"][0].heroSlides[_type == "pageSlide"] {
                ...,
                page -> {
                	...,
              	}
            }
        },
        _type == "aboutUs" => {
            aboutUsPage -> {
                slug,
            }
        },
        _type == "newsSection" => {
            featuredNews[]->{
              ...,
            },
            newsPage->{
                ...,
              },
        },
        _type == "transactionsSection" => {
            featuredTransactions[]->{
              ...,
              company->{
                ...,
              }
            },
            transactionsPage->{
                ...,
              },
        },
        _type == "slide" => {
            slides[] -> {
                ...,
            }
        },
    }
}
`

const Page = ({ data, preview }) => {
  const router = useRouter()

  if (!router.isFallback && !data.page?.slug?.current) {
    return <ErrorPage statusCode={404} />
  }

  const { data: { content = [] } = {} } = usePreviewSubscription(PAGE_QUERY, {
    params: { slug: data?.page?.slug?.current },
    initialData: data?.page,
    enabled: preview || router.query.preview !== null,
  })

  return <article>{content && <RenderSections sections={content} />}</article>
}

export const getStaticPaths = async () => {
  return {
    paths: [],
    fallback: true,
  }
}

export const getStaticProps = async ({ params, preview = false }) => {
  const page = await getClient(preview).fetch(PAGE_QUERY, params)

  return {
    props: {
      preview,
      data: { page },
    },
  }
}

export default Page
Aug 24, 2021, 9:10 AM
deskStructure.js

import * as React from 'react'
import { MdSettings } from 'react-icons/md'

const SitePreview = ({ document }) => {
  if (!process.env.SANITY_STUDIO_PREVIEW_URL) {
    console.warn(
      'SANITY_STUDIO_PREVIEW_URL should be set for preview to work! Falling back to localhost:3000',
    )
  }

  let slug
  switch (document.displayed._type) {
    case 'page':
      slug = document.displayed.slug.current
      break
    case 'news':
      slug = `nyheter/${document.displayed.slug.current}`
      break
    case 'transaction':
      slug = `transaktioner/${document.displayed.slug.current}`
      break
    default:
      break
  }

  console.log(document, slug)

  return (
    <iframe
      title={document.displayed._id}
      src={`${
        process.env.SANITY_STUDIO_PREVIEW_URL ?? '<http://localhost:3000>'
      }/${slug}?preview`}
      style={{ width: '100%', height: '100%', border: 0 }}
    /&gt;
  )
}

export const getDefaultDocumentNode = () =&gt; {
  // Conditionally return a different configuration based on the schema type
  return S.document().views([
    S.view.form(),
    S.view.component(SitePreview).title('Preview'),
  ])
}
Aug 24, 2021, 9:12 AM
This is page route file in Next.js and the deskstructure file in sanity studio. I’ve pretty much followed the “Usage” section here: https://github.com/sanity-io/next-sanity#usage
Aug 24, 2021, 9:13 AM
Any Idéas?
user M
Aug 30, 2021, 7:51 AM
Any Idéas?
user M
Aug 30, 2021, 7:51 AM
Hey (Removed Name)! I'm afraid I'm not sure here. I suggest you take a look at this new guide on implementing preview with Next. It might help!
Aug 31, 2021, 12:48 AM
Hey (Removed Name)! I'm afraid I'm not sure here. I suggest you take a look at this new guide on implementing preview with Next. It might help!
Aug 31, 2021, 12:48 AM
Okay thank you! 🙂
Aug 31, 2021, 8:34 AM
Let us know if it doesn't help and we can debug!
Aug 31, 2021, 5:39 PM
Hi
user M
I’ve gotten to about this step: https://www.sanity.io/guides/nextjs-live-preview#a0974373a20e But the content is not updating with the changes i make (without publishing)
and Preview remains True even tho i click the button with exit-preview.
Sep 2, 2021, 10:38 AM
// pages/index.js

import Link from 'next/link'

import Layout from '../components/Layout'
import { filterDataToSingleItem } from '../components/methods'
import { RenderSections } from '../components/RenderSections'
import { usePreviewSubscription } from '../lib/sanity'
import { getClient } from '../lib/sanity.server'
import { PAGE_QUERY } from '../queries/page'
import { SETTINGS_QUERY } from '../queries/settings'

export const getStaticProps = async ({ preview = false }) =&gt; {
  const config = await getClient(preview).fetch(SETTINGS_QUERY)

  const queryParams = { slug: config?.frontpage?.slug?.current }
  const data = await getClient(preview).fetch(PAGE_QUERY, queryParams)

  if (!data) return { notFound: true }

  const page = filterDataToSingleItem(data, preview)

  return {
    props: {
      preview,
      data: { page, query: PAGE_QUERY, queryParams },
      config,
    },
  }
}

const Home = ({ data, preview, config }) =&gt; {
  const { data: previewData } = usePreviewSubscription(data?.query, {
    params: data?.queryParams ?? {},
    initialData: data?.page,
    enabled: preview,
  })

  const { content = [] } = filterDataToSingleItem(previewData, preview)

  return (
    &lt;Layout config={config}&gt;
      {preview &amp;&amp; &lt;Link href="/api/exit-preview"&gt;Preview Mode Activated!&lt;/Link&gt;}
      &lt;article&gt;{content &amp;&amp; &lt;RenderSections sections={content} /&gt;}&lt;/article&gt;
    &lt;/Layout&gt;
  )
}

export default Home
Sep 2, 2021, 10:39 AM
// pages/api/preview.js

export default function preview(req, res) {
  if (!req?.query?.secret) {
    return res.status(401).json({ message: 'No secret token' })
  }

  // Check the secret and next parameters
  // This secret should only be known to this API route and the CMS
  if (req.query.secret !== process.env.SANITY_PREVIEW_SECRET) {
    return res.status(401).json({ message: 'Invalid secret token' })
  }

  if (!req.query.slug) {
    return res.status(401).json({ message: 'No slug' })
  }

  // Enable Preview Mode by setting the cookies
  res.setPreviewData({})

  // Redirect to the path from the fetched post
  // We don't redirect to req.query.slug as that might lead to open redirect vulnerabilities
  res.writeHead(307, {
    Location: req.query.slug === '/' ? '/' : `/${req?.query?.slug}` ?? '/',
  })

  return res.end()
}
Sep 2, 2021, 10:40 AM
// pages/api/exit-preview.js

export default function exit(req, res) {
  res.clearPreviewData()

  res.writeHead(307, { Location: req?.query?.slug ?? '/' })
}
Sep 2, 2021, 10:40 AM
// utils/resolveProductionUrl.js (studio)

export default function resolveProductionUrl(doc) {
  const baseUrl =
    process.env.SANITY_STUDIO_PREVIEW_URL || '<http://localhost:3000>'

  const previewUrl = new URL(baseUrl)

  previewUrl.pathname = '/api/preview'
  previewUrl.searchParams.append(
    'secret',
    process.env.SANITY_STUDIO_PREVIEW_SECRET,
  )

  const slug = doc?.slug?.current === 'home' ? '/' : doc?.slug?.current

  previewUrl.searchParams.append('slug', slug ?? '/')

  return previewUrl.toString()
}
Sep 2, 2021, 10:41 AM
And I’ve copied the
lib/
folder from next/sanity utilities package
Sep 2, 2021, 10:43 AM
And I’ve copied the
lib/
folder from next/sanity utilities package
Sep 2, 2021, 10:43 AM
Okay I’ve solved those two issues.1. My query was only getting the first page type and not an array so the filterDataToSingleItem wasn’t returning the correct data.
2. The exit preview just kept loading. Added
res.end()
at the end of the exit-preview file and it worked.
Sep 2, 2021, 11:05 AM
Okay ’ve followed the complete guide now and it looks to be working correctly!I have one question about the split plane view, it seems to only update when refreshing the iframe/site and doesn’t update right away. Anyway to fix this?
Sep 2, 2021, 1:46 PM
Nice! Glad you got it working. I'm not sure on the split pane question, though. I'll have to look into that!
Sep 2, 2021, 5:12 PM
Hey
user C
, I’ve been looking at this guide and I’ve had some questions as well. Like you, I added req.end() as per Vercel’s own example (which differs in some regards). My issue now is that Next.js complains about not being able to load the script exit-preview.js.
Sep 9, 2021, 11:13 AM
Unhandled Runtime Error

Error: Failed to load script: /_next/static/chunks/pages/api/exit-preview.js


Call Stack

HTMLScriptElement.script.onerror

node_modules/next/dist/client/route-loader.js (83:51)
Sep 9, 2021, 11:13 AM
I’ve run into the same issue when checking out the repository linked in to in the guide. Also, I’ve exhausted all other ways of figuring this out – hate to have to bother the community with this because I have the feeling that something fairly “simple” is behind this. If anyone has some insights or wisdom here, it would be much appreciated 🙏
Sep 9, 2021, 11:15 AM
That’s strange, I didn’t get any error like that when exiting the preview. How does your exit-preview file look?
user D
Sep 9, 2021, 1:13 PM
That’s strange, I didn’t get any error like that when exiting the preview. How does your exit-preview file look?
Sep 9, 2021, 1:13 PM
Indeed strange, hence the hesitation to ask the community.
export default function exit(req, res) {

res.clearPreviewData();

`res.writeHead(307, { Location: req?.query?.slug ??
/
});`

res.end();

}
Sep 9, 2021, 1:32 PM
I lifted it off the repo and added the
res.end();
myself.
Sep 9, 2021, 1:33 PM
yeah it’s the exact same as mine. How do you link to it? Or does it fail before starting/building the app?
Sep 9, 2021, 1:35 PM
`&lt;Link href={
/api/exit-preview?slug=${asPath}
}&gt;Preview Mode Activated!&lt;/Link&gt;` which is the same as in the repo `&lt;Link href={
/api/exit-preview?slug=${asPath}
}&gt;Preview Mode Activated!&lt;/Link&gt;` (copied)
Sep 9, 2021, 1:39 PM
Note that the error message displays, and then the page returns the the production page
Sep 9, 2021, 1:40 PM
export default async function exit(_, res) {
  // Exit the current user from "Preview Mode". This function accepts no args.
  res.clearPreviewData()

  // Redirect the user back to the index page.
  res.writeHead(307, { Location: '/' })
  res.end()
}

Sep 9, 2021, 1:41 PM
yeah it’s the exact same as mine. How do you link to it? Or does it fail before starting/building the app?
Sep 9, 2021, 1:35 PM
In my humbleness, I’ve also been figuring that it’s easier to return the user to the index if you have multiple types of paths to preview
Sep 9, 2021, 1:42 PM
I trust that this may be relevant as well for completeness:
Sep 9, 2021, 1:43 PM
"dependencies": {
    "next": "11.1.2",
    "next-sanity": "^0.4.0",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  },
  "devDependencies": {
    "eslint": "7.32.0",
    "eslint-config-next": "11.1.2"
  }

Sep 9, 2021, 1:43 PM
My Link, have you tried it without the slug parameter?
 &lt;Link href="/api/exit-preview"&gt;
   &lt;button
     as="a"&gt;
     Exit Preview
   &lt;/button&gt;
 &lt;/Link&gt;
Maybe could see if downgrading next does anything?

  "dependencies": {
    "next": "latest",
    "next-sanity": "^0.4.0",
    "react": "^17.0.1",
    "react-dom": "^17.0.1",
  }

next: "10.2.3" (from node modules)
Otherwise im not sure what could be causing this. We are using very similar codes, maybe
user M
can give her thoughts 🙂
Sep 9, 2021, 2:08 PM
I’ll give downgrading a shot, thanks!
Sep 9, 2021, 2:08 PM
Going down to next 11.0 and next-sanity 0.2.0 does the trick, I’ll investigate in which version this occurs and will report (something must be wrong, smarter people probably need to know).
Sep 9, 2021, 2:13 PM
Using the slug only works for published documents obviously, one should handle that.
Sep 9, 2021, 2:13 PM
Thanks (Removed Name)!
Sep 9, 2021, 2:13 PM
Great! 👍
Sep 9, 2021, 2:34 PM
Great! 👍
Sep 9, 2021, 2:34 PM
user C
, this behavior appears with next@11.0.2 and next-sanity@0.2.0
Sep 10, 2021, 9:15 AM
It works fine with next@11.0.2 and the latest next-sanity@0.4.0
Sep 10, 2021, 9:17 AM
I won’t be in a position to report this to Vercel and the Next.js maintainers anytime soon unfortunately. Will do when able to. Take care!
Sep 10, 2021, 9:20 AM

Sanity– build remarkable experiences at scale

The Sanity Composable Content Cloud is the headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.

Was this answer helpful?

Categorized in