Как я могу реализовать гиперссылку в этом коде?

За этой проблемой стоит много информации. Я постараюсь здесь все показать.

Я использую Hygraph и GraphQL для создания блога с помощью Headless CMS, и при вызове API у меня есть getPostDetails. Это работает, и моя проблема связана с контентом {raw}.

          export const getPostDetails = async (slug) => {
      const query = gql`
        query GetPostDetails($slug: String!) {
          post(where: {slug: $slug}) {
            title
            excerpt
            featuredImage {
              url
            }
            author{
              name
              bio
              photo {
                url
              }
            }
            createdAt
            slug
            content {
              raw 
            }
            categories {
              name
              slug
            }
          }
        }
      `;
    
      const result = await request(graphqlAPI, query, { slug });
    
      return result.post;
    };

Мне нужно было создать способ рендеринга всех узлов, которые предоставляет гиграф при создании текста. В качестве примера я использовал контент, который я видел в этом видео (здесь) на 2:01:36, подробности статьи.

      'use client'

import React, { useEffect, useState } from 'react';
import { getPostDetails } from '@/app/api';
import { Flex, Grid, GridItem, Heading, Image, Link, Text } from '@chakra-ui/react';
import AdAside from '../../UI/Atoms/AdAside';

export default function PostPage({ params: { slug }}) {
  const getContentFragment = (index, text, obj, type) => {
    let modifiedText = text;

    if (obj) {
      if (obj.bold) {
        modifiedText = (<b key={index}>{text}</b>);
      }

      if (obj.italic) {
        modifiedText = (<em key={index}>{text}</em>);
      }

      if (obj.underline) {
        modifiedText = (<u key={index}>{text}</u>);
      }

      if (obj.link) {
        modifiedText = (<a key={index} href={obj.nodeId}>{text}</a>);
      }
      
    }

    switch (type) {
      case 'heading-three':
        return <Heading as='h3' key={index}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Heading>;
      case 'paragraph':
        return <Text key={index} maxWidth="1200px" mb={8}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Text>;
      case 'heading-four':
        return <Heading as='h4' key={index}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Heading>;
      case 'image':
        return (
          <Image
            key={index}
            alt={obj.title}
            height={obj.height}
            width={obj.width}
            src={obj.src}
          />
        );
      case 'link':
      return <Link key={index} href={obj.nodeId}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Link>

      default:
        return modifiedText;
    }
  };

  const [pagePost, setPagePost] = useState(null);

  useEffect(() => {
    const fetchPost = async () => {
      try {
        if (slug) {
          const result = await getPostDetails(slug);
          setPagePost(result);
        }
      } catch (error) {
        console.error(error);
      }
    };

    fetchPost();
    console.log(pagePost)
  }, [slug]);

  if (!pagePost) {
    return <div>Loading...</div>;
  }
  
  return (
    <>
    <Image
      w="100vw" 
      maxHeight='600px' 
      objectFit='cover' 
      alt='banner content' 
      src={pagePost.featuredImage.url}
      />
    <Grid 
    templateColumns="repeat(12, 1fr)" 
    gap={1} 
    px={6} 
    py={10}
    >
      <GridItem 
      gridColumn={{ base: 'span 12', lg: 'span 8' }}
      >
      <Flex 
      maxWidth="1200px" 
      flexDirection="column"
       >
        <Heading textAlign='left' mb={16}>
          {pagePost.title}
          </Heading>
        <Flex 
        textAlign="left" 
        flexDirection="column"
        >
        {pagePost.content.raw.children.map((typeObj, index) => {
          const children = typeObj.children.map((item, itemindex) => getContentFragment(itemindex, item.text, item));
          
          return getContentFragment(index, children, typeObj, typeObj.type);
        })}
        </Flex>

      </Flex>
      </GridItem>
      <GridItem gridColumn={{ base: 'span 12', lg: 'span 4' }}>
        <AdAside />
      </GridItem>
    </Grid>
      
    </>
  );
}

Если вы посмотрите видео, вы это увидите

            if (obj.link) {
        modifiedText = (<a key={index} href={obj.nodeId}>{text}</a>);
      }

и

      case 'link':
      return <Link key={index} href={obj.nodeId}>{modifiedText.map((item, i) => <React.Fragment key={i}>{item}</React.Fragment>)}</Link>

не существуют там. Я включил попытку найти способ использовать гиперссылки. Кроме того, я заглянул на площадку Hygraph Playground, чтобы увидеть, что связано со «ссылкой», и там тоже есть свойства: nodeId и Href.

Содержимое с гиперссылкой не отображается, и я не знаю, что делаю неправильно. Я хочу использовать nodeId для перехода от одного сообщения блога к другому и использовать гиперссылку для отправки пользователя на внешний веб-сайт.

Вы можете помочь мне?

1 ответ

Ответ прост. Как вы можете видеть, вы проверяете ссылку так же, как вы проверяете жирный шрифт или курсив, но если вы обратите пристальное внимание, ваш идентификатор ссылки находится на верхнем уровне и/или включен в ключ типа.

Итак, первое, что вам следует ожидать, это соответствие типа ссылке, а неobj.linkвам следует проверить:

      if(obj.type === 'link') {
  modifiedText = (<a key={index} href={obj.href}>
    {getContentFragment(0, obj.children[0].text, obj.children, obj.children.props)}
  </a>)
}

Вы видите, что ссылка внутри происходит, потому что, когда у вас естьtype === "link"ваш текст должен находиться внутри дочерних элементов, а не быть родственнымobj.type

Другие вопросы по тегам