--- 如何使用 React-Markdown 详细指南

如何使用 React-Markdown 详细指南

详细介绍如何在 React 项目中使用 React-Markdown 库来解析和渲染 Markdown 内容,包含简洁的代码示例和统一模板使用方法

2025-09-03

作者:naiko

The Astro logo on a dark background with a pink glow.

react

markdown

react-markdown

前端开发

文本渲染

如何使用 React-Markdown 详细指南

本文档将用简单易懂的方式介绍如何在 React 项目中使用 React-Markdown 库,以及如何创建统一的 Markdown 渲染模板,让所有 Markdown 文件都能保持一致的样式和行为。

什么是 React-Markdown?

React-Markdown 是一个 React 库,它能把 Markdown 文本转换成 React 组件,而不是直接转换成 HTML。这样做更安全,也更容易定制样式和行为。

为什么要使用 React-Markdown?

安装 React-Markdown

首先,在你的项目中安装 React-Markdown:

# 使用 npm
npm install react-markdown

# 使用 pnpm
pnpm add react-markdown

基础用法:快速开始

下面是最简单的使用方式,让你快速上手:

示例 1:最基础的 Markdown 渲染

import React from 'react';
import ReactMarkdown from 'react-markdown';

const SimpleMarkdown = () => {
  // 你的 Markdown 内容
  const markdownText = `# 欢迎使用 React-Markdown

这是**粗体文本**,这是*斜体文本*。

## 简单列表
- 项目一
- 项目二
- 项目三`;

  return (
    <div className="markdown-wrapper">
      <ReactMarkdown>{markdownText}</ReactMarkdown>
    </div>
  );
};

export default SimpleMarkdown;

解释

  1. 导入 React 和 ReactMarkdown 组件
  2. 定义一个包含 Markdown 格式的字符串
  3. 用 ReactMarkdown 组件包裹这个字符串,就能自动渲染成对应的 HTML 样式

示例 2:从外部加载 Markdown 内容

实际项目中,我们通常从文件或 API 获取 Markdown:

import React, { useState, useEffect } from 'react';
import ReactMarkdown from 'react-markdown';

const ExternalMarkdown = () => {
  const [content, setContent] = useState('');
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // 模拟从 API 或文件加载 Markdown
    const loadMarkdown = async () => {
      try {
        setIsLoading(true);
        // 真实项目中,这里会是:const response = await fetch('/api/article');
        // 然后:const text = await response.text();
        
        // 模拟加载延迟
        await new Promise(resolve => setTimeout(resolve, 300));
        
        // 模拟获取到的 Markdown 内容
        const markdownFromApi = `# 从外部加载的文章

这是一篇从**服务器**获取的文章。\n\n> 这是一段引用文字\n\n[点击查看更多](https://example.com)`;
        
        setContent(markdownFromApi);
      } catch (error) {
        console.error('加载 Markdown 失败:', error);
      } finally {
        setIsLoading(false);
      }
    };

    loadMarkdown();
  }, []);

  if (isLoading) {
    return <div>加载中...</div>;
  }

  return (
    <div className="markdown-wrapper">
      <ReactMarkdown>{content}</ReactMarkdown>
    </div>
  );
};

export default ExternalMarkdown;

解释

创建统一的 Markdown 模板组件

为了让所有 Markdown 文件都使用同一套样式和配置,我们可以创建一个可复用的模板组件。

步骤 1:创建基础的 Markdown 模板组件

src/ReactComponents 目录下创建一个 MarkdownRenderer.jsx 文件:

import React from 'react';
import ReactMarkdown from 'react-markdown';
import './MarkdownStyle/style.css'; // 用于统一的样式

// 基础的 Markdown 渲染器组件
const MarkdownRenderer = ({ children }) => {
  return (
    <div className="unified-markdown-container">
      <ReactMarkdown>{children}</ReactMarkdown>
    </div>
  );
};

export default MarkdownRenderer;

步骤 2:添加统一的样式文件

src/ReactComponents/MarkdownStyle 目录下创建 style.css 文件:

/* Markdown 统一样式 */
.unified-markdown-container {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
  line-height: 1.6;
  color: #333;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
}

.unified-markdown-container h1 {
  color: #2c3e50;
  font-size: 2rem;
  margin-bottom: 1rem;
  border-bottom: 2px solid #eee;
  padding-bottom: 0.5rem;
}

.unified-markdown-container h2 {
  color: #34495e;
  font-size: 1.5rem;
  margin-top: 2rem;
  margin-bottom: 1rem;
}

.unified-markdown-container p {
  margin-bottom: 1rem;
}

.unified-markdown-container strong {
  font-weight: 600;
  color: #2c3e50;
}

.unified-markdown-container em {
  font-style: italic;
}

.unified-markdown-container ul, 
.unified-markdown-container ol {
  margin-bottom: 1rem;
  padding-left: 1.5rem;
}

.unified-markdown-container li {
  margin-bottom: 0.5rem;
}

.unified-markdown-container a {
  color: #3498db;
  text-decoration: none;
}

.unified-markdown-container a:hover {
  text-decoration: underline;
}

.unified-markdown-container blockquote {
  border-left: 4px solid #3498db;
  padding-left: 1rem;
  margin-left: 0;
  color: #7f8c8d;
  font-style: italic;
}

.unified-markdown-container pre {
  background-color: #f8f9fa;
  padding: 1rem;
  border-radius: 4px;
  overflow-x: auto;
  margin-bottom: 1rem;
}

.unified-markdown-container code {
  font-family: 'Consolas', 'Monaco', monospace;
  background-color: #f8f9fa;
  padding: 0.2rem 0.4rem;
  border-radius: 3px;
  font-size: 0.9em;
}

步骤 3:如何在项目中引用这个模板

现在,你可以在项目的任何地方引用这个统一的 Markdown 模板:

import React from 'react';
import MarkdownRenderer from '../ReactComponents/MarkdownRenderer';

const MyBlogPage = () => {
  // 你的 Markdown 内容
  const blogContent = `# 我的博客文章

这是使用**统一模板**渲染的博客文章。

## 文章内容
- 这是第一点
- 这是第二点

> 这是一段引用文字`;

  return (
    <div className="blog-page">
      <h1>博客页面</h1>
      <MarkdownRenderer>{blogContent}</MarkdownRenderer>
    </div>
  );
};

export default MyBlogPage;

为什么要这样做?

如何让所有 Markdown 都使用这一套模板

要让项目中的所有 Markdown 文件都使用同一套模板,你可以这样做:

方法 1:在 Astro 项目中统一处理

如果你的项目使用 Astro,你可以修改 src/layouts/MarkdownPostLayout.astro 文件:

---
import MarkdownRenderer from '../ReactComponents/MarkdownRenderer';

const { content } = Astro.props;
---

<article class="post">
  <header class="post-header">
    <h1>{content.title}</h1>
    <p class="post-date">{content.pubDate}</p>
  </header>
  
  <!-- 使用我们的统一 Markdown 渲染器 -->
  <div class="post-content">
    <MarkdownRenderer>
      {content.body}
    </MarkdownRenderer>
  </div>
</article>

方法 2:为 API 返回的 Markdown 内容创建包装器

对于从 API 获取的 Markdown 内容,你可以创建一个包装组件:

import React, { useEffect, useState } from 'react';
import MarkdownRenderer from './MarkdownRenderer';

// 通用的 API Markdown 加载组件
const ApiMarkdownLoader = ({ url }) => {
  const [markdown, setMarkdown] = useState('');
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchMarkdown = async () => {
      try {
        setIsLoading(true);
        setError(null);
        
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error('请求失败');
        }
        
        const text = await response.text();
        setMarkdown(text);
      } catch (err) {
        setError(err);
      } finally {
        setIsLoading(false);
      }
    };

    if (url) {
      fetchMarkdown();
    }
  }, [url]);

  if (isLoading) {
    return <div className="loading">加载中...</div>;
  }

  if (error) {
    return <div className="error">加载失败: {error.message}</div>;
  }

  return (
    <div className="api-markdown-content">
      <MarkdownRenderer>{markdown}</MarkdownRenderer>
    </div>
  );
};

export default ApiMarkdownLoader;

然后在需要加载 Markdown 的地方使用:

import React from 'react';
import ApiMarkdownLoader from './ApiMarkdownLoader';

const HelpPage = () => {
  return (
    <div className="help-page">
      <h1>帮助中心</h1>
      <ApiMarkdownLoader url="/api/help-content" />
    </div>
  );
};

export default HelpPage;

简单的高级功能:自定义样式和组件

添加代码高亮(可选,但常用)

如果你想为代码块添加语法高亮,可以安装 react-syntax-highlighter

npm install react-syntax-highlighter

然后更新 MarkdownRenderer.jsx

import React from 'react';
import ReactMarkdown from 'react-markdown';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism';
import './MarkdownStyle/style.css';

const MarkdownRenderer = ({ children }) => {
  // 自定义代码块渲染
  const components = {
    code: ({ inline, className, children }) => {
      // 检查是否是代码块(非内联代码)
      const match = /language-(\w+)/.exec(className || '');
      
      if (!inline && match) {
        // 代码块,使用语法高亮
        return (
          <SyntaxHighlighter
            language={match[1]}
            style={tomorrow}
            className="custom-code-block"
          >
            {String(children)}
          </SyntaxHighlighter>
        );
      }
      
      // 内联代码,保持默认样式
      return <code className={className}>{children}</code>;
    }
  };

  return (
    <div className="unified-markdown-container">
      <ReactMarkdown components={components}>{children}</ReactMarkdown>
    </div>
  );
};

export default MarkdownRenderer;

在 Markdown 中使用 React 组件

你还可以在 Markdown 中直接使用 React 组件,让内容更丰富:

import React from 'react';
import MarkdownRenderer from './MarkdownRenderer';

// 定义一个简单的提示框组件
const NoteBox = ({ children }) => {
  return (
    <div style={{
      backgroundColor: '#f8f9fa',
      borderLeft: '4px solid #3498db',
      padding: '12px',
      margin: '16px 0',
      borderRadius: '4px'
    }}>
      {children}
    </div>
  );
};

const AdvancedMarkdownPage = () => {
  // 在 Markdown 中使用 React 组件
  const markdownWithComponents = `# 高级 Markdown 示例

这是一个普通段落。

<NoteBox>
  这是一个**提示框**,它是用 React 组件实现的!
</NoteBox>

## 下面是代码示例

\`\`\`javascript
function sayHello() {
  console.log('Hello from React-Markdown!');
}
\`\`\``;

  // 将自定义组件传递给 MarkdownRenderer
  const customComponents = {
    NoteBox
  };

  return (
    <div className="advanced-markdown-page">
      <MarkdownRenderer components={customComponents}>
        {markdownWithComponents}
      </MarkdownRenderer>
    </div>
  );
};

export default AdvancedMarkdownPage;

注意:要在 MarkdownRenderer.jsx 中添加 components 属性的支持:

const MarkdownRenderer = ({ children, components = {} }) => {
  // ... 其他代码不变 ...
  return (
    <div className="unified-markdown-container">
      <ReactMarkdown 
        components={{ ...defaultComponents, ...components }} 
      >
        {children}
      </ReactMarkdown>
    </div>
  );
};

总结

通过本文的指南,你应该已经了解:

  1. 基础使用:如何安装和基本使用 React-Markdown
  2. 创建模板:如何创建统一的 Markdown 渲染模板
  3. 统一应用:如何让所有 Markdown 文件都使用同一套模板
  4. 简单扩展:如何添加代码高亮和在 Markdown 中使用 React 组件

使用统一的 Markdown 模板可以让你的项目保持一致的风格,同时也方便后续的维护和更新。无论是博客、文档还是帮助中心,React-Markdown 都能帮助你高效地渲染和管理 Markdown 内容。