We first install npm install --save react-markdown
and import it into the project, and the npm official website has an introduction to usage.
react-markdown has many attributes that can be customized. The complete code is as follows:
import React from 'react';
import moment from "moment";
import ReactMarkdown from "react-markdown";
// 这里引入自定义组件
import {
code, h1, h2, h3, h4, a, blockquote, li} from './Markdown'
import remarkGfm from 'remark-gfm'
import remarkMath from 'remark-math'
import rehypeKatex from 'rehype-katex'
import 'katex/dist/katex.min.css' // `rehype-katex` does not import the CSS for you
import Link from "next/link";
const PostDetail = ({
post}) => {
return (
...
// tailwindcss
<div className="lg:p-4 p-2">
<ReactMarkdown
className=""
// 传入markdown文本内容
children={
post.content}
remarkPlugins={
[remarkGfm, remarkMath]}
rehypePlugins={
[rehypeKatex]}
components={
{
code: code,
h1: h1,
h2: h2,
h3: h3,
h4: h4,
a: a,
blockquote: blockquote,
li:li
}}
/>
</div>
);
};
export default PostDetail;
From the above, our custom component styles are all there Markdown.jsx中
, let's take a look:
import React from 'react';
import {
Prism as SyntaxHighlighter} from "react-syntax-highlighter";
// 注意,这里有坑
import {
oneDark as codeStyle} from "react-syntax-highlighter/dist/cjs/styles/prism";
// 定义一个代码块样式,官网给出的案例
export const code = ({
node, inline, className, children, ...props}) => {
const match = /language-(\w+)/.exec(className || '')
// 判断是行内代码,还是独立代码块
return !inline && match ? (
<SyntaxHighlighter
children={
String(children).replace(/\n$/, '')}
style={
codeStyle}
language={
match[1]}
PreTag="div"
{
...props}
/>
) : (
<span className="text-sm mx-1" style={
{
color: '#c7254e', backgroundColor: '#f9f2f4', borderRadius: '2px'}}>
{
children}
</span>
// <code className={className} {...props}>
// {children}
// </code>
)
}
// h1组件自定义
export const h1 = ({
node, ...props}) => {
return (
<div className="text-2xl mt-5 mb-3 font-bold" {
...props} />
);
};
export const h2 = ({
node, ...props}) => {
return (
<div className="text-xl mt-3 mb-1 font-bold" {
...props} />
);
};
export const h3 = ({
node, ...props}) => {
return (
<div className="text-lg mt-2 mb-1 font-bold" {
...props} />
);
};
export const h4 = ({
node, ...props}) => {
return (
<div className="mt-2 mb-1 font-bold" {
...props} />
);
};
// 链接组件自定义
export const a = ({
node, ...props}) => {
return (
<a href={
node.properties.href} target="_blank"
className="text-blue-600 hover:text-blue-500 mx-1 rounded-sm hover:shadow-md font-serif underline cursor-pointer" {
...props} />
);
};
// 引用组件自定义
export const blockquote = ({
node, ...props}) => {
return (
<div className="my-2 bg-gray-300 shadow-md font-serif rounded-lg p-4" {
...props}/>
);
};
// li组件自定义
export const li = ({
node, ...props}) => {
// 注意,li的父组件可能为无序的<ul></ul>和有序的<ol></ol>
// 根据不同的父组件渲染不同组件
// props中ordered属性判断是有序还是无序
// 如果有序props中的index为序号索引,一般加一显示
if (props.ordered) {
return (
<div className="flex shadow-md my-2 font-serif rounded-lg p-1">
{
props.index + 1}. <div className="ml-2" {
...props}/>
</div>
)
}
// 无序渲染一个svg
return (
<div className="flex items-center shadow-md my-2 font-serif rounded-lg p-1 ">
<span>
<svg t="1669231142038"
onClick={
() => {
window.open("https://www.mcdonalds.com.cn/")
}}
className="icon h-5 w-5 mr-2 hover:cursor-pointer hover:scale-105 transition duration-75"
viewBox="0 0 1024 1024" version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="8368" width="200" height="200">
<path>...</path>
</svg>
</span>
<div {
...props}/>
</div>
);
};
Note that import {oneDark as codeStyle} from "react-syntax-highlighter/dist/cjs/styles/prism";
there is a pit introduced above. The official website allows us to import import {dark} from 'react-syntax-highlighter/dist/esm/styles/prism'
, but importing according to the official website will report an error, see StackOverflow: SyntaxError: Unexpected token 'export' in Next.js
In addition, for the formula display react-markdown
in the component , there is a version bug, which will cause the formula to display garbled characters, and react reports the following error:katex
Hydration failed because the initial UI does not match what was rendered on
After testing, it was because of the Next version. After I downgraded from version 13.0.4 to version 13.0.0, the formula displayed normally, and the react version remained unchanged: "react": "18.2.0","react-dom": "18.2.0"
.
In this way, a simple markdown display completes: