React博客中HTML-React-Parser解析TinyMCE内容报错:参数需为字符串
问题:使用HTML-React-Parser转换HTML时出现
TypeError: First argument must be a string错误 我基于React和Material UI开发博客,用户通过TinyMCE提交的文章以原始HTML格式存储在JSON文件中。在单篇文章详情组件中使用HTML-React-Parser将HTML转换为可读格式时,出现上述错误。
相关组件代码:
import * as React from 'react'; import { Container } from '@mui/system'; import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Card, CardMedia, Typography } from '@mui/material'; import parse from 'html-react-parser'; const SinglePost = () => { let { singlePostId } = useParams(); const [latestPost, setLatestPost] = useState(''); useEffect(() => { fetch(`http://localhost:8000/posts/${singlePostId}`) .then ((res) => { return res.json(); }) .then ((data) => { setLatestPost(data); }); }, [singlePostId]); return ( <> <Container maxWidth="md"> <Card> <CardMedia component="img" image={latestPost.url} /> <Typography variant="h5"> {latestPost.title} </Typography> <Typography variant="h6"> {latestPost.category} </Typography> <Typography variant="body5"> {parse(latestPost.body)} //this is the prop that should be parsed </Typography> </Card> </Container> </> ); } export default SinglePost;
我尝试过以下两种写法,但问题仍未解决:
<div>{parse(latestPost.body)}</div>
{parse(`latestPost.body`)}
原因分析
- 初始状态不匹配:你把
latestPost的初始状态设为空字符串'',但fetch成功后设置的是一个包含title、body等字段的对象。组件首次渲染时,latestPost是字符串,访问latestPost.body会得到undefined,而html-react-parser的parse方法要求第一个参数必须是字符串,传入undefined就会触发报错。 - 错误的模板字符串用法:
parse(latestPost.body)是把字符串字面量"latestPost.body"传给了parse,而不是变量latestPost.body的值,这完全不符合需求,自然无法解决问题。
解决方案
1. 修正初始状态并添加空值兜底
把latestPost的初始状态设为空对象,同时在调用parse时给latestPost.body加兜底值,确保传入的始终是字符串:
import * as React from 'react'; import { Container } from '@mui/system'; import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Card, CardMedia, Typography } from '@mui/material'; import parse from 'html-react-parser'; const SinglePost = () => { let { singlePostId } = useParams(); // 初始化为空对象,而非空字符串 const [latestPost, setLatestPost] = useState({}); useEffect(() => { fetch(`http://localhost:8000/posts/${singlePostId}`) .then((res) => res.json()) .then((data) => { setLatestPost(data); }); }, [singlePostId]); return ( <> <Container maxWidth="md"> <Card> <CardMedia component="img" image={latestPost.url || ''} /> <Typography variant="h5"> {latestPost.title || ''} </Typography> <Typography variant="h6"> {latestPost.category || ''} </Typography> {/* 注意:Material UI没有body5变体,改为body1或body2 */} <Typography variant="body1"> {/* 用|| ''确保传入parse的是字符串 */} {parse(latestPost.body || '')} </Typography> </Card> </Container> </> ); } export default SinglePost;
2. 增加加载状态(推荐)
为了避免数据加载完成前渲染无效内容,可以添加加载状态,确保仅当数据加载完成后才调用parse:
import * as React from 'react'; import { Container } from '@mui/system'; import { useEffect, useState } from 'react'; import { useParams } from 'react-router-dom'; import { Card, CardMedia, Typography } from '@mui/material'; import parse from 'html-react-parser'; const SinglePost = () => { let { singlePostId } = useParams(); const [latestPost, setLatestPost] = useState({}); const [isLoading, setIsLoading] = useState(true); useEffect(() => { fetch(`http://localhost:8000/posts/${singlePostId}`) .then((res) => res.json()) .then((data) => { setLatestPost(data); setIsLoading(false); }) .catch(err => { console.error('加载文章失败:', err); setIsLoading(false); }); }, [singlePostId]); // 加载中显示占位内容 if (isLoading) { return <Container maxWidth="md"><Typography variant="body1">加载中...</Typography></Container>; } return ( <> <Container maxWidth="md"> <Card> <CardMedia component="img" image={latestPost.url || ''} /> <Typography variant="h5"> {latestPost.title || ''} </Typography> <Typography variant="h6"> {latestPost.category || ''} </Typography> <Typography variant="body1"> {parse(latestPost.body || '')} </Typography> </Card> </Container> </> ); } export default SinglePost;
额外注意点
- Material UI的
Typography组件没有body5这个变体,建议使用官方提供的body1(默认正文)或body2(小号正文)。 - 给所有从
latestPost读取的字段加|| ''兜底,可以避免因接口返回字段缺失导致的其他渲染错误。
内容的提问来源于stack exchange,提问作者postmetric
相关产品推荐
相关产品推荐

