) {
return (
{node.children?.map((child: any, i: number) =>
renderNode && ctx
? renderNode(child, `${String(indexKey)}-link-${i}`, ctx)
: null,
)}
)
}
setCustomComponents('docs', {
heading: CustomHeading,
link: CustomLink,
})
export function Article({ markdown }: { markdown: string }) {
return
}
```
常见映射可以这样理解:
- `h1` ... `h6` -> `heading` + `node.level`
- `a` -> `link`
- `p` -> `paragraph`
- `img` -> `image`
- `code` / `pre` -> `code_block` 或 `inline_code`
- 自定义 HTML-like 标签 -> `customHtmlTags` + `setCustomComponents`
## 迁移代码高亮
很多 `react-markdown` 项目会通过覆盖 `components.code` 接第三方高亮器。
到了 `markstream-react`,一般有三种选择:
- 继续使用默认 `CodeBlockNode`,拿到 Monaco 驱动的代码块体验。
- 把 `code_block` 切到 `MarkdownCodeBlockNode`,使用更轻量的 Shiki 方案。
- 设置 `renderCodeBlocksAsPre`,直接回退到普通 ``。
下面是切到 Shiki 的例子:
```tsx
import MarkdownRender, { MarkdownCodeBlockNode, setCustomComponents } from 'markstream-react'
setCustomComponents('docs', {
code_block: ({ node, isDark, ctx }: any) => (
),
})
export function Article({ markdown }: { markdown: string }) {
return
}
```
## 迁移插件逻辑
### `remarkPlugins`
如果你之前用 `remarkPlugins` 做语法扩展,最接近的迁移点是 `customMarkdownIt`。
```tsx
import type { MarkdownIt } from 'markdown-it-ts'
import { full as markdownItEmoji } from 'markdown-it-emoji'
import MarkdownRender from 'markstream-react'
function withEmoji(md: MarkdownIt) {
md.use(markdownItEmoji)
return md
}
export function Article({ markdown }: { markdown: string }) {
return
}
```
### `rehypePlugins`
`markstream-react` 里没有直接对等的 `rehype` 阶段。
如果你原来的 `rehype` 逻辑是为了做这些事:
- HTML 树重写:迁到自定义节点渲染器或节点后处理。
- 自定义 HTML-like block:优先改成 `customHtmlTags`。
- 安全过滤:改用 `parseOptions.validateLink`、自定义渲染器或节点过滤。
## HTML、自定义标签与安全
`react-markdown` 默认通常会转义 HTML,除非你显式加上 `rehypeRaw`。
`markstream-react` 会直接解析 HTML-like 节点,而且内置 HTML 渲染器会去掉被拦截的标签、危险事件属性以及不安全的 URL。
如果你以前接 `rehypeRaw` 主要是为了支持 `` 这类自定义标签,推荐迁移方式如下:
```tsx
import type { NodeComponentProps } from 'markstream-react'
import MarkdownRender, { setCustomComponents } from 'markstream-react'
function ThinkingNode({ node }: NodeComponentProps) {
return
}
setCustomComponents('chat', { thinking: ThinkingNode })
export function Message({ markdown }: { markdown: string }) {
return (
)
}
```
## 流式升级路径
你不需要第一天就把流式能力全部接上。比较实用的迁移路径是:
1. 先把 `react-markdown` 换成 `MarkdownRender`,继续使用 `content`。
2. 再迁移自定义渲染器和插件逻辑。
3. 如果后面要接 SSE / 聊天流输出,再把解析挪到组件外,改传 `nodes`。
```tsx
import MarkdownRender from 'markstream-react'
import { getMarkdown, parseMarkdownToStructure } from 'stream-markdown-parser'
const md = getMarkdown('chat')
const nodes = parseMarkdownToStructure(buffer, md, { final: done })
export function Message() {
return (
)
}
```
对于高频流式输出来说,这个 `nodes` 方案通常就是迁移到 `markstream-react` 的最大价值之一。
## 迁移检查清单
- 把 `{markdown}` 改成 ``
- 引入 `markstream-react/index.css`
- 把 `components` 覆盖迁到 `setCustomComponents(customId, mapping)`
- 先删除已经冗余的插件,再按需补回真正还需要的能力
- 重新检查任何依赖 `rehype` 的 HTML 过滤或变换逻辑
- 如果你的应用要渲染增量输出,进一步从 `content` 升级到解析后的 `nodes`
## 相关文档
- [React 安装](/zh/guide/react-installation)
- [React 组件与 API](/zh/guide/react-components)
- [解析器 API](/zh/guide/parser-api)