How to fix the "Unknown block type" error in Portable Text with custom components.

16 replies
Last updated: Dec 21, 2022
Hello, I am fetching a doc like this :
const main = await sanity.fetch(groq
    `*[_type == "pages"][pageSlug.current == $pageSlug][0]{
      'hero': blockContent[_type == 'hero'],
      'platforms': blockContent[_type == 'platforms']
    }
    `,{pageSlug}
    )
I am using Portable Text to display components,

const ptComponents = {
    // Components for totally custom types outside the scope of Portable Text
    types: {
        hero: Main,
        platforms: Platforms
    },
  
    // Overrides for specific block styles - in this case just the `h2` style
    block: {
     
    },
  
    // Implements a custom component to handle the `schnauzer` list item type
    list: {
     
    },
  
    // Custom components for marks - note that `link` overrides the default component,
    // while the others define components for totally custom types.
    marks: {

    },
  }

<PortableText components={ptComponents} value={props.main} />
Eventually I get this error

[@portabletext/react] Unknown block type "undefined", specify a component for it in the `components.types` prop
How can I fix this please??
Dec 21, 2022, 10:22 PM
This might help: Disabling warnings / handling unknown types

To disable this behavior, you can either pass
false
to the
onMissingComponent
property, or give it a custom function you want to use to report the error.
Dec 21, 2022, 10:33 PM
user J
Thank you! But I am not sure how can I do it in my case 😅
Dec 21, 2022, 10:38 PM
The issue is coming from the props
main
, this is the array I am passing
Dec 21, 2022, 10:41 PM
So somewhere in your portable text is a block type you did not define.If you read through the ReadMe this error about undefined type is mentioned, but wait...
I am also wondering, why you are querying for your block content in the way you do…
This way you do not get an array of blocks as an output but just objects…
Dec 21, 2022, 10:43 PM
(as you just posted here )
Dec 21, 2022, 10:43 PM
If I put in the values something like
props.main.hero
the hero component will be displayed
Dec 21, 2022, 10:43 PM
Perhaps the way I defined the query isnt helpful for this case
Dec 21, 2022, 10:44 PM
this
const main = await sanity.fetch(groq
    `*[_type == "pages"][pageSlug.current == $pageSlug][0]{
      'hero': blockContent[_type == 'hero'],
      'platforms': blockContent[_type == 'platforms']
    }
    `,{pageSlug}
    )

Dec 21, 2022, 10:45 PM
This is the way you need to query for portable text (this is a different example then yours but you will get the main idea)
Dec 21, 2022, 10:45 PM
This is another example of one of my own portable text queries:

const query = `[]{body[]{ ...,  
    _type == "file" => {..., "url": @.asset->url},  
    _type == "internalBtn" => { 
        "reference": @.reference->_type,
        "slug": "/"+  @.reference-> slug.current },
    _type == "testimonial" => {..., "reference": @->}, 
    markDefs[]{ 
        ..., 
        _type == "internalLink" => { "slug": "/"+ @.reference-> slug.current },
        _type == "publication" =>  {..., "reference": @->{url, title, description, "file": @.file.asset->url } },
        _type == "job" =>  {"reference": @->{url, title, description, location} }
        },
    }`;
Dec 21, 2022, 10:46 PM
This is another example of one of my own portable text queries:

const query = `*[_type == 'pages' && pageSlug.current == $pageSlug][0]{
...,
  body[]{ 
     ...,  
    _type == "file" => {..., "url": @.asset->url},  
    _type == "testimonial" => {..., "reference": @->}, 
    markDefs[]{ 
        ..., 
        _type == "internalLink" => { "slug": "/"+ @.reference-> slug.current },
        _type == "publication" =>  {..., "reference": @->{url, title, description, "file": @.file.asset->url } },
        _type == "job" =>  {"reference": @->{url, title, description, location} }
        },
    }`;

Dec 21, 2022, 10:48 PM
Oh I understand, I am just curious, I think I shouldn't add dynamic Components this way? Initially this object I am trying to display in the frontend is not coming from a portable text editor, instead it's an array of different types
hero
and
platforms
Dec 21, 2022, 10:51 PM
then you can pass the body array to the PortableText component like this
<PortableText components={PTcomponents} value={props.body} />
But you need to define what to serialise for each value like file in that case:

const PTcomponents = {
    types: {
      file: (props) => {
        return (
          <Button
            href={props.value.url + "?dl"}
            color={color || "carrot"}
            className={ButtonClassName + " mr-2"}
            border={borderInternal}
          >
            {props.value.title || "Download"}
          </Button>
        );
      },
//YOUR OTHER SERIALIZERS AND MARKS 
marks: {
      internalLink: ({value, children}) => {
        return (
          <Link href={value.slug}>
            <a className="underline">
              {children}{" "}
              <BsSignpost className="inline mb-1 text-grey opacity-30" />
            </a>
          </Link>
        );
      },
}}}
Dec 21, 2022, 10:52 PM
Wow, thats really helpful, truly thankful!!
Dec 21, 2022, 10:52 PM
wait one edit ☝️
Dec 21, 2022, 10:53 PM
Happy I could help!
Dec 21, 2022, 10:54 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.

Was this answer helpful?