Trouble using LiteYouTubeEmbed component in Portable Text for Next.js

1 replies
Last updated: Jan 6, 2023
I'm trying to follow this guide to add a youtube embed to portable text and render it in a Next js frontend. I am able to get the data from portable text and display a link to the video in the front end, but when I try to use the
LiteYouTubeEmbed
component to render the Youtube embed I get
Unhandled Runtime Error

Error: React__namespace.useState is not a function
Does anyone have an updated example of how to do this?
Here's my portable text component:

import 'react-lite-youtube-embed/dist/LiteYouTubeEmbed.css'

import { PortableText, PortableTextComponents } from '@portabletext/react'
import { LaunchIcon,LinkIcon } from '@sanity/icons'
import ImageBox from 'components/shared/ImageBox'
import { TimelineSection } from 'components/shared/TimelineSection'
import getYouTubeId from 'get-youtube-id'
import { resolveHref } from 'lib/sanity.links'
import Link from 'next/link'
import React from 'react'
import LiteYouTubeEmbed from 'react-lite-youtube-embed';
import { Block, Image } from 'sanity'

export function CustomPortableText({
  paragraphClasses,
  value,
}: {
  paragraphClasses?: string
  value: Block[]
}) {
  const components: PortableTextComponents = {
    block: {
      normal: ({ children }) => {
        return <p className={paragraphClasses}>{children}</p>
      },
    },
    marks: {
      link: ({ children, value }) => {
        return (
          <>
            <a
              className="underline transition hover:opacity-50"
              href={value?.href}
              target={value?.blank ? '_blank' : '_self'}
              rel="noreferrer noopener"
            >
              {children}
              <LaunchIcon className='inline'/>
            </a>
            
          </>
        )
      },
      internalLink: ({children, value}) => {
        console.log(value)
        return  (
          <>
            <Link
              className="underline transition hover:opacity-50"
              href={resolveHref(value?.toType, value?.slug)}
            >
                {children}
                <LinkIcon className='inline'/>
            </Link>
            
          </>
        )
      }
    },
    types: {
      image: ({
        value,
      }: {
        value: Image & { alt?: string; caption?: string }
      }) => {
        return (
          <div className="my-6 space-y-2">
            <ImageBox
              image={value}
              alt={value.alt}
              classesWrapper="relative aspect-[16/9]"
            />
            {value?.caption && (
              <div className="font-sans text-sm text-gray-600">
                {value.caption}
              </div>
            )}
          </div>
        )
      },
      timeline: ({ value }) => {
        const { items } = value || {}
        return <TimelineSection timelines={items} />
      },
      youtube: ({value}) => {
        const { url } = value
        const id = getYouTubeId(url)
        return (
          <LiteYouTubeEmbed
            aspectHeight = {9}
            aspectWidth = {16}
            id={id}
            title={value.alt}
          />
          // <a href={value.url}>{value.alt}</a> // adding a link to youtube works fine
          // LiteYouTubeEmbed causes Unhandled Runtime Error: React__namespace.useState is not a function
        )
      }
    },
  }

  return <PortableText components={components} value={value} />
}

Jan 6, 2023, 4:53 PM
For now I got it working using an iframe instead of using LiteYouTubeEmbed
youtube: ({value}) => {
        const { url } = value
        const id = getYouTubeId(url)
        return (
          <div className=" w-full aspect-w-16 aspect-h-9">
            <iframe
              src={`<https://www.youtube.com/embed/${id}>`}
              title={value.alt}
              allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
              allowFullScreen
            ></iframe>
          </div>
        )
      }
Jan 6, 2023, 5:42 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?