Astro中如何向React/Preact组件传递Markdown组件?
在React/Preact组件中使用Astro Markdown组件的正确方式
问题描述
我想把Markdown组件导入到React/Preact组件中,直接导入无法正常工作,于是尝试从父Astro组件传入,代码如下:
<DemoContent blog={(<Blog />)} tweet={(<TweetThread />)} highlight={(<HighlightClips />)} client:visible />
但报错:ERROR: Expected ">" but found "/",请问正确的实现方式是什么?
解决方案1:传递原始Markdown字符串,在React组件中解析
这种方式安全可控,通过Astro的?raw后缀获取Markdown文件的原始内容,传递给React组件后用react-markdown库渲染。
- Astro父组件代码:
--- import DemoContent from './DemoContent.jsx'; // 用?raw获取Markdown文件的原始字符串 import blogContent from './blog.md?raw'; import tweetContent from './tweet-thread.md?raw'; import highlightContent from './highlight-clips.md?raw'; --- <DemoContent blog={blogContent} tweet={tweetContent} highlight={highlightContent} client:visible />
- React/Preact组件代码:
import ReactMarkdown from 'react-markdown'; export default function DemoContent({ blog, tweet, highlight }) { return ( <div> <section> <h2>博客内容</h2> <ReactMarkdown>{blog}</ReactMarkdown> </section> <section> <h2>推文线程</h2> <ReactMarkdown>{tweet}</ReactMarkdown> </section> <section> <h2>高亮片段</h2> <ReactMarkdown>{highlight}</ReactMarkdown> </section> </div> ); }
解决方案2:将Markdown组件渲染为HTML字符串传递
如果已经在Astro中处理好Markdown的样式和渲染,可以用Astro的renderToString方法把Markdown组件转成HTML字符串,再传给React组件用dangerouslySetInnerHTML渲染(仅在内容可信时使用)。
- Astro父组件代码:
--- import DemoContent from './DemoContent.jsx'; import Blog from './blog.md'; import TweetThread from './tweet-thread.md'; import HighlightClips from './highlight-clips.md'; // 导入Astro的渲染方法 import { renderToString } from 'astro/runtime/server/render'; // 将Markdown组件渲染为HTML字符串 const blogHtml = await renderToString(Blog); const tweetHtml = await renderToString(TweetThread); const highlightHtml = await renderToString(HighlightClips); --- <DemoContent blog={blogHtml} tweet={tweetHtml} highlight={highlightHtml} client:visible />
- React/Preact组件代码:
export default function DemoContent({ blog, tweet, highlight }) { return ( <div> <section> <h2>博客内容</h2> <div dangerouslySetInnerHTML={{ __html: blog }} /> </section> <section> <h2>推文线程</h2> <div dangerouslySetInnerHTML={{ __html: tweet }} /> </section> <section> <h2>高亮片段</h2> <div dangerouslySetInnerHTML={{ __html: highlight }} /> </section> </div> ); }
解决方案3:使用Astro插槽(Slot)传递组件
Astro支持插槽机制,可以把Markdown组件放在React组件的指定插槽中,避免props传递的语法问题。
- Astro父组件代码:
--- import DemoContent from './DemoContent.jsx'; import Blog from './blog.md'; import TweetThread from './tweet-thread.md'; import HighlightClips from './highlight-clips.md'; --- <DemoContent client:visible> <div slot="blog"> <Blog /> </div> <div slot="tweet"> <TweetThread /> </div> <div slot="highlight"> <HighlightClips /> </div> </DemoContent>
- React/Preact组件代码:
export default function DemoContent({ children }) { // 筛选对应插槽的内容 const getSlotContent = (slotName) => { return children.find(child => child.props.slot === slotName); }; return ( <div> <section> <h2>博客内容</h2> {getSlotContent('blog')} </section> <section> <h2>推文线程</h2> {getSlotContent('tweet')} </section> <section> <h2>高亮片段</h2> {getSlotContent('highlight')} </section> </div> ); }
原方法报错原因
Astro的JSX编译逻辑和React不同,直接将JSX元素作为props传递给React组件会触发语法解析错误,因为Astro无法正确处理这种嵌套的JSX写法。上述三种方法都避开了这个问题,适配了Astro和React/Preact的交互逻辑。
内容的提问来源于stack exchange,提问作者Cassidy
相关产品推荐
相关产品推荐

