Migrating to @portabletext/react and encountering issues with the "value" property.
28 replies
Last updated: Feb 20, 2022
N
Currently using the older PortableText plugin react-portable-text but I would like to migrate to _*@portabletext/react.* Doing so, it’s asking to add a value instead of content. using the older plugin I specify in Nextjs the content from the post.bo _dy from my Sanity GROQ query. But moving this to value is not working. What should go inside the value now? It’s not so clear from the documentation really.
My PortableText the value is wrong.. I am trying to load all the post->body content inside the value. But now it’s giving me errors.
const query = `*[_type == "post" && slug.current == $slug][0] { _id, _createdAt, title, description, mainImage, slug, body[]{ ..., asset -> { ..., "_key": _id } }, 'comments': *[ _type == "comment" && post._ref == ^._id && approved == true ], author -> { name, image } }`;
<PortableText value={post.body} components={{ types: { image: ({ asset, alt, width }) => ( <figure className="inline-image"> <img src={urlFor(asset).width(width).fit("max").url()} alt={alt} /> <figcaption> {caption && <span className="float-left">{caption}</span>} {credit && ( <i className="float-right">Photo credit: {credit}</i> )} </figcaption> </figure> ), }, block: { h1: (props: any) => ( <h1 className="text-2xl font-bold my-5" {...props} /> ), h2: (props: any) => ( <h2 className="text-xl font-bold my-5" {...props} /> ), h3: (props: any) => ( <h3 className="text-lg font-bold my-5" {...props} /> ), h4: (props: any) => ( <h4 className="text-md font-bold my-5" {...props} /> ), blockquote: (props: any) => ( <blockquote className="text-xl text-red-300 font-bold my-5" {...props} /> ), }, marks: { link: ({ href, children }: any) => ( <a href={href} className="text-blue-500 hover:underline"> {children} </a> ), }, listItem: { li: ({ children }: any) => ( <li className="ml-4 list-disc">{children}</li> ), }, }} />
Feb 19, 2022, 12:04 AM
N
user M
Take a look at the “value” I am passing the GROQ’s post->body to itFeb 19, 2022, 12:13 AM
N
This
Feb 19, 2022, 12:16 AM
N
When I remove the types => image it works.
Feb 19, 2022, 12:16 AM
Ah, the issue is with your asset being undefined, not with value not being passed in then. I don't think the way you're querying images inside of block content correctly.
Feb 19, 2022, 12:19 AM
N
But I have an image in the content editor but it returns undefined.
Feb 19, 2022, 12:22 AM
The way you currently have it set you're adding a field called
assetto each block. When a block doesn't have an asset to expand, it sets it to
null. You're passing in a
nullvalue into your serializer that is now running on each block.
Feb 19, 2022, 12:26 AM
N
user A
Now it’s saying:
TypeError: Cannot read properties of undefined (reading ‘asset’)
Feb 19, 2022, 12:33 AM
N
import Header from "@components/Header"; import { sanityClient, urlFor } from "sanity"; import { Post } from "typings"; import { GetStaticProps } from "next"; // import PortableText from "react-portable-text"; import { PortableText } from "@portabletext/react"; interface Props { post: Post; } function Post({ post }: Props) { console.log(post); return ( <main> <Header /> <img className="w-full h-40 object-cover" src={urlFor(post.mainImage).url()!} /> <article className="max-w-3xl mx-auto p-5"> <h1 className="text-3xl mt-10 mb-3">{post.title}</h1> <h2 className="text-xl font-light text-gray-500 mb-2"> {post.description} </h2> <div className="flex items-center space-x-2"> <img className="h-10 w-10 rounded-full object-cover" src={urlFor(post.author.image).url()} /> <p className="font-extralight text-sm"> Blog post by{" "} <span className="text-green-600">{post.author.name}</span> - Published at{" "} {new Date(post._createdAt).toLocaleDateString("nl-NL", { year: "numeric", month: "2-digit", day: "2-digit", })} </p> </div> <div className="mt-10"> <PortableText value={post.body} components={{ types: { image: ({ node: { asset, alt, width } }: any) => ( <figure className="inline-image"> <img alt={alt} src={urlFor(asset).width(1280).fit("max").url()} /> </figure> ), }, block: { h1: ({ children }) => ( <h1 className="text-2xl font-bold my-5">{children}</h1> ), h2: ({ children }) => ( <h2 className="text-xl font-bold my-5">{children}</h2> ), h3: ({ children }) => ( <h3 className="text-lg font-bold my-5">{children}</h3> ), h4: ({ children }) => ( <h4 className="text-md font-bold my-5">{children}</h4> ), // blockquote: (props: any) => ( // <blockquote // className="text-xl text-red-300 font-bold my-5" // {...props} // /> // ), }, marks: { // link: ({ href, children }: any) => ( // <a href={href} className="text-blue-500 hover:underline"> // {children} // </a> // ), }, listItem: { li: ({ children }: any) => ( <li className="ml-4 list-disc">{children}</li> ), }, }} /> </div> <hr className="my-5 border border-yellow-500 mb-10" /> <h3 className="text-sm text-yellow-500">Enjoyed this article?</h3> <h4 className="text-3xl font-bold">Leave a comment below!</h4> <hr className="py-3 mt-2" /> <form className="flex flex-col py-5 mx-auto mb-10"> <label className="block mb-5"> <span className="text-gray-700">Name</span> <input className="shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 outline-none focus:ring" placeholder="John Appleseed" type="text" /> </label> <label className="block mb-5"> <span className="text-gray-700">Email</span> <input className="shadow border rounded py-2 px-3 form-input mt-1 block w-full ring-yellow-500 outline-none focus:ring" placeholder="John Appleseed" type="text" /> </label> <label className="block mb-5"> <span className="text-gray-700">Comment</span> <textarea className="shadow border rounded py-2 px-3 form-textarea mt-1 block w-full ring-yellow-500 outline-none focus:ring" placeholder="John Appleseed" rows={8} /> </label> </form> </article> </main> ); } export default Post; export const getStaticPaths = async () => { const query = `*[_type == "post"] { title, slug { current } }`; const posts = await sanityClient.fetch(query); const paths = posts.map((post: Post) => ({ params: { slug: post.slug.current, }, })); return { paths, fallback: "blocking", }; }; export const getStaticProps: GetStaticProps = async ({ params }) => { const query = `*[_type == "post" && slug.current == $slug][0] { _id, _createdAt, title, description, mainImage, slug, body[]{ ..., asset -> { alt, width, ..., "_key": _id } }, 'comments': *[ _type == "comment" && post._ref == ^._id && approved == true ], author -> { name, image } }`; const post = await sanityClient.fetch(query, { slug: params?.slug, }); if (!post) { return { notFound: true, }; } return { props: { post, }, revalidate: 60, // After 60 seconds update old cached version. }; };
Feb 19, 2022, 12:41 AM
What does your query in getStaticProps return when you run it in Vision and pass the slug that’s causing this error?
Feb 19, 2022, 1:00 AM
N
Give me one sec
Feb 19, 2022, 1:01 AM
N
When passing only “body” to the. GROQ in the vision. I get all body items including the type image and the asset.
Feb 19, 2022, 1:08 AM
N
But on the front-end it wont show
Feb 19, 2022, 1:08 AM
Can you try removing the projection under
body[]? As Racheal pointed out, asking for
assetexplicitly will look for it on every block. If you must drill down to do your
_keything, you’ll want to do so conditionally.
// ... description, mainImage, slug, body[], 'comments': *[ // ...
Feb 19, 2022, 1:15 AM
Can you try removing the projection under
body[]? As Racheal pointed out, asking for it explicitly will cause it to look for it on everything.
// ... description, mainImage, slug, body[], 'comments': *[ // ...
Feb 19, 2022, 1:15 AM
N
Now I have this:
const query = `*[_type == "post" && slug.current == $slug][0] { _id, _createdAt, title, description, mainImage, slug, body[], 'comments': *[ _type == "comment" && post._ref == ^._id && approved == true ], author -> { name, image } }`; types: { image: ({ node: { asset, alt, width } }) => ( <figure className="inline-image"> <img src={urlFor(asset).width(1280).fit("max").url()} /> </figure> ), }, },
TypeError: Cannot read properties of undefined (reading 'asset')
Feb 19, 2022, 1:18 AM
N
The “node” does nothing when i console log post.body I get an array of types including the image type where the _ref is defined. But I keep getting undefined asset. Asset is not recognized while Sanity vision shows everything correctly.
Feb 19, 2022, 1:34 AM
N
The H1,H2,H3,H4, LI, OL everything works else
Feb 19, 2022, 1:36 AM
N
The H1,H2,H3,H4, LI, OL everything works else
Feb 19, 2022, 1:36 AM
N
Isn’t “node” used for GraphQL?
Feb 19, 2022, 1:40 AM
That suggestion was before knowing you had switched to the new portable text renderer. I would try switching it back to what you had before.
Although
Although
nodeis found in GraphQL, it's also a prop from some block content types.
Feb 19, 2022, 2:13 AM
N
user A
I have switched to the new new portable text like you have suggested. Why is the image not working? Changed the query and still no luckFeb 19, 2022, 2:15 AM
Can you try
valueinstead of
node? https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md#new-component-properties
Feb 19, 2022, 2:48 AM
Can you try
valueinstead of
node? https://github.com/portabletext/react-portabletext/blob/main/MIGRATING.md#new-component-properties
Feb 19, 2022, 2:48 AM
N
user A
That was it!!! 😄 Could you please, explain me where does the “value” comes from the plugin? Because I don’t see it in the GROQ query.Feb 19, 2022, 11:47 AM
N
Thanks
user M
and user A
Feb 19, 2022, 11:48 AM
Glad to hear it, Nino.
valuecomes from the renderer rather than being a property on your content, so you won’t see it in a GROQ query.
Feb 19, 2022, 3:48 PM
Sanity– build remarkable experiences at scale
Sanity is a modern headless CMS that treats content as data to power your digital business. Free to get started, and pay-as-you-go on all plans.