You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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`)}

原因分析

  1. 初始状态不匹配:你把latestPost的初始状态设为空字符串'',但fetch成功后设置的是一个包含title、body等字段的对象。组件首次渲染时,latestPost是字符串,访问latestPost.body会得到undefined,而html-react-parser的parse方法要求第一个参数必须是字符串,传入undefined就会触发报错。
  2. 错误的模板字符串用法: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 02:01:13