React+Gatsby+Contentful项目中富文本列表重复显示问题求助
问题:React/Gatsby + Contentful 文章列表中Rich Text字段重复显示,无法对应单篇文章摘要
问题描述
我在基于React和Gatsby的项目中使用Contentful作为内容源,Content模型里大部分是普通字符串字段,只有最后一个是Rich Text类型。我想实现文章列表卡片,展示标题、发布日期和简短摘要,所以重置了Rich Text的格式让它像普通文本。但渲染列表时,普通字段显示正常,Rich Text字段却在每个卡片里重复显示,没法对应每篇文章的唯一摘要。我试了几种方法都没解决,以下是页面代码:
import React from "react" import { graphql } from 'gatsby' import { BLOCKS, MARKS } from "@contentful/rich-text-types" import { renderRichText } from "gatsby-source-contentful/rich-text" import Layout from "../components/base/layout" import { PageWrapper, BlogCardWrapper, BlogCardElement, ThumbnailImage, ContentInlineWrapper, PreContentParagraph, ReadMoreParagraph, BlogTitleHeader, BlogDateParagraph, } from "../styles/aktualnosci.style" import { Headers } from "../utils/data/headersData" import H1 from "../components/headers/h1" const AktualnosciPage = ({ data }) => { const articles = data.allContentfulArtykul.edges const post = articles[0].node.content const option = { renderNode: { [BLOCKS.EMBEDDED_ASSET]: node => { return <img/> }, [BLOCKS.HEADING_1]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, [BLOCKS.HEADING_5]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, [BLOCKS.PARAGRAPH]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, [BLOCKS.QUOTE]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, [BLOCKS.UL_LIST]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, [BLOCKS.LIST_ITEM]: (node, children) => { return <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p> }, }, renderMark: { [MARKS.BOLD]: (node, children) => { return <p style={{fontWeight: '100'}}>{children}</p> }, } } const output = renderRichText(post, option) return ( <Layout> <PageWrapper> <H1 name={ Headers.Aktualnosci }/> <BlogCardWrapper> {articles.reverse().map(({node}) => { return ( <div key={node.slug}> <a href={"/aktualnosci/" + node.slug}> <BlogCardElement> <ThumbnailImage className="j10_dfg4gvBDG" src={node.thumbnailPhoto.fluid.src} srcSet={node.thumbnailPhoto.fluid.srcSet} /> <ContentInlineWrapper> <BlogTitleHeader>{node.title}</BlogTitleHeader> <PreContentParagraph>{output}</PreContentParagraph> <BlogDateParagraph>{node.createdAt}</BlogDateParagraph> </ContentInlineWrapper> <ReadMoreParagraph className="j5_dfg4gvBDG">Czytaj więcej <span style={{color: '#BF1E2D', fontSize: '11px'}}>➤</span></ReadMoreParagraph> </BlogCardElement> </a> </div> ) })} </BlogCardWrapper> </PageWrapper> </Layout> ) } export const query = graphql` query { allContentfulArtykul { edges { node { id thumbnailPhoto { fluid { src srcSet } } title slug content { raw references { ... on ContentfulAsset { __typename contentful_id fixed(width: 200) { src srcSet } } } } createdAt(formatString: "YYYY-MM-DD") } } } } ` export default AktualnosciPage
解决方案
问题出在你提前只渲染了第一篇文章的Rich Text内容(const post = articles[0].node.content),然后在循环所有文章时,每个卡片都复用了这个output变量——相当于所有卡片都在显示第一篇文章的摘要,自然会重复。
你需要把Rich Text的渲染逻辑放到循环内部,让每篇文章都用自己的node.content来生成对应的摘要。具体修改如下:
- 保留
option配置(可以放在组件内部任意位置,不影响) - 删除全局的
post和output变量 - 在
map循环中,对当前遍历到的node的content调用renderRichText
修改后的核心代码片段:
const AktualnosciPage = ({ data }) => { const articles = data.allContentfulArtykul.edges // 保留原有的Rich Text渲染配置 const option = { renderNode: { [BLOCKS.EMBEDDED_ASSET]: node => <img/>, [BLOCKS.HEADING_1]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, [BLOCKS.HEADING_5]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, [BLOCKS.PARAGRAPH]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, [BLOCKS.QUOTE]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, [BLOCKS.UL_LIST]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, [BLOCKS.LIST_ITEM]: (node, children) => <p style={{padding: '0', margin: '0', display: 'inline-block'}}>{children}</p>, }, renderMark: { [MARKS.BOLD]: (node, children) => <p style={{fontWeight: '100'}}>{children}</p>, } } return ( <Layout> <PageWrapper> <H1 name={ Headers.Aktualnosci }/> <BlogCardWrapper> {articles.reverse().map(({node}) => { // 关键:在循环内为当前文章单独渲染Rich Text const postOutput = renderRichText(node.content, option) return ( <div key={node.slug}> <a href={"/aktualnosci/" + node.slug}> <BlogCardElement> <ThumbnailImage className="j10_dfg4gvBDG" src={node.thumbnailPhoto.fluid.src} srcSet={node.thumbnailPhoto.fluid.srcSet} /> <ContentInlineWrapper> <BlogTitleHeader>{node.title}</BlogTitleHeader> {/* 使用当前文章的渲染结果 */} <PreContentParagraph>{postOutput}</PreContentParagraph> <BlogDateParagraph>{node.createdAt}</BlogDateParagraph> </ContentInlineWrapper> <ReadMoreParagraph className="j5_dfg4gvBDG">Czytaj więcej <span style={{color: '#BF1E2D', fontSize: '11px'}}>➤</span></ReadMoreParagraph> </BlogCardElement> </a> </div> ) })} </BlogCardWrapper> </PageWrapper> </Layout> ) }
这样每篇文章都会渲染自己的Rich Text内容,就不会出现重复的问题了。另外,如果你需要控制摘要长度,建议在Contentful中单独添加一个“摘要”字符串字段,这样比处理整个Rich Text内容更高效,也能避免格式处理的麻烦。
内容的提问来源于stack exchange,提问作者Raczek
相关产品推荐
相关产品推荐

