React组件中ReactDom.render返回类型不匹配FC的问题如何解决?
React FC组件返回类型不匹配问题解决
问题背景
核心需求是实现Markdown渲染,同时解析传入的HTML格式字符串。已知children为HTML字符串,且isParseRequired参数设为true。使用TypeScript编写的Markdown组件出现TypeScript类型错误。
原组件代码
import cx from 'classnames' import 'github-markdown-css' import 'katex/dist/katex.min.css' import { FC, ReactNode, useEffect, useMemo, useState } from 'react' import { CopyToClipboard } from 'react-copy-to-clipboard' import { BsClipboard } from 'react-icons/bs' import ReactDom from 'react-dom' import ReactMarkdown from 'react-markdown' import reactNodeToString from 'react-node-to-string' import rehypeHighlight from 'rehype-highlight' import remarkBreaks from 'remark-breaks' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' import supersub from 'remark-supersub' import Tooltip from '../Tooltip' import './markdown.css' const Markdown: FC<{ children: string, isParseRequired?: boolean}> = ({ children, isParseRequired = false }) => { return ReactDom.render( <ReactMarkdown remarkPlugins={[remarkMath, supersub, remarkBreaks, remarkGfm]} rehypePlugins={[[rehypeHighlight, { detect: true, ignoreMissing: true }]]} className={`markdown-body markdown-custom-styles !text-base font-normal`} linkTarget="_blank" components={{ a: ({ node, ...props }) => { if (!props.title) { return <a {...props} /> } return ( <Tooltip content={props.title}> <a {...props} title={undefined} /> </Tooltip> ) }, code: ({ node, inline, className, children, ...props }) => { if (inline) { return ( <code className={className} {...props}> {children} </code> ) } return <CustomCode className={className}>{children}</CustomCode> }, }} children={children}/>, document.body) } export default Markdown
错误信息
src/app/components/Markdown/index.tsx:48:7 - error TS2322: Type '({ children, isParseRequired }: { children: string; isParseRequired?: boolean | undefined; }) => void | Element' is not assignable to type 'FC<{ children: string; isParseRequired?: boolean | undefined; }>'.
问题原因
React函数组件(FC)要求返回ReactNode类型的JSX元素,而ReactDom.render的返回值是渲染出的DOM元素或void,与FC的返回类型不匹配。另外,ReactDom.render是用于将React应用挂载到根DOM节点的方法,不能在组件内部用来生成返回内容。
解决方法
修改后的组件代码
import cx from 'classnames' import 'github-markdown-css' import 'katex/dist/katex.min.css' import { FC, ReactNode, useMemo } from 'react' import { CopyToClipboard } from 'react-copy-to-clipboard' import { BsClipboard } from 'react-icons/bs' import ReactMarkdown from 'react-markdown' import reactNodeToString from 'react-node-to-string' import rehypeHighlight from 'rehype-highlight' import remarkBreaks from 'remark-breaks' import remarkGfm from 'remark-gfm' import remarkMath from 'remark-math' import supersub from 'remark-supersub' import Tooltip from '../Tooltip' import './markdown.css' // 补充原代码中缺失的CustomCode组件 const CustomCode: FC<{ className?: string; children: ReactNode }> = ({ className, children }) => { return ( <div className="code-block-wrapper"> <CopyToClipboard text={String(children)}> <button className="copy-button"> <BsClipboard /> </button> </CopyToClipboard> <pre className={className}> <code>{children}</code> </pre> </div> ) } const Markdown: FC<{ children: string; isParseRequired?: boolean }> = ({ children, isParseRequired = false }) => { // 根据isParseRequired动态配置rehype插件,添加HTML解析能力 const rehypePlugins = useMemo(() => { const basePlugins = [[rehypeHighlight, { detect: true, ignoreMissing: true }]] if (isParseRequired) { // 需先安装依赖:npm install rehype-raw const rehypeRaw = require('rehype-raw').default basePlugins.push(rehypeRaw) } return basePlugins }, [isParseRequired]) return ( <ReactMarkdown remarkPlugins={[remarkMath, supersub, remarkBreaks, remarkGfm]} rehypePlugins={rehypePlugins} className={`markdown-body markdown-custom-styles !text-base font-normal`} linkTarget="_blank" components={{ a: ({ node, ...props }) => { if (!props.title) { return <a {...props} /> } return ( <Tooltip content={props.title}> <a {...props} title={undefined} /> </Tooltip> ) }, code: ({ node, inline, className, children, ...props }) => { if (inline) { return ( <code className={className} {...props}> {children} </code> ) } return <CustomCode className={className}>{children}</CustomCode> }, }} children={children} /> ) } export default Markdown
关键修改点
- 移除组件内部的
ReactDom.render调用,直接返回<ReactMarkdown>JSX元素,符合FC组件的返回类型要求 - 补充原代码中未定义的
CustomCode组件,避免运行时错误 - 新增
isParseRequired逻辑:当需要解析HTML时,引入rehype-raw插件(需先执行npm install rehype-raw安装依赖) - 使用
useMemo缓存插件数组,避免组件每次渲染时重复创建插件列表,优化性能
内容的提问来源于stack exchange,提问作者ishandutta2007
相关产品推荐
相关产品推荐

