直接返回React组件失效,React.cloneElement生效的问题排查
问题描述
我想根据API返回的文件类型构建一个可条件渲染的图标字典,但在FileIconMapper.jsx里直接返回<Icon size="40px" color="red" />时触发错误:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method ofFileIconMapper.
只有用React.cloneElement(Icon)才能正常渲染,其他React组件不用克隆就能正常工作。我怀疑是react-bootstrap-icons库的问题,试过用{}包裹渲染也没用。
项目依赖配置:
{ ... "dependencies": { "next": "^13.2.3", "react": "18.2.0", "react-bootstrap": "^2.7.2", "react-bootstrap-icons": "^1.10.2", "react-datepicker": "^4.10.0", "react-dom": "18.2.0", "react-select": "^5.7.0", }, ... }
问题原因
react-bootstrap-icons导出的图标并不是标准的React组件函数/类,而是已经实例化的React元素对象,不是可直接调用的组件类型。直接用JSX语法<Icon />相当于尝试渲染一个对象,而非组件,所以触发报错。
解决方案
方案1:存储组件本身,渲染时传入props
把图标组件(而非实例化后的元素)存入字典,渲染时再通过JSX语法传入size、color等属性:
import { FileText, Image, Pdf } from 'react-bootstrap-icons'; // 字典存储组件类型 const iconMap = { txt: FileText, img: Image, pdf: Pdf }; const FileIconMapper = ({ fileType }) => { const IconComponent = iconMap[fileType]; // 存在对应组件则渲染,否则返回null return IconComponent ? <IconComponent size="40px" color="red" /> : null; };
方案2:用React.cloneElement复用已配置的元素实例
如果需要提前配置好图标属性并存入字典,就用React.cloneElement来克隆已有的元素实例进行渲染:
import { FileText, Image } from 'react-bootstrap-icons'; import React from 'react'; // 字典存储已配置好的元素实例 const iconMap = { txt: <FileText size="40px" color="red" />, img: <Image size="40px" color="blue" /> }; const FileIconMapper = ({ fileType }) => { const iconElement = iconMap[fileType]; return iconElement ? React.cloneElement(iconElement) : null; };
为什么其他组件没问题?
其他React组件(比如自定义组件、react-bootstrap的内置组件)导出的是组件类或函数,属于可直接调用的组件类型,因此可以直接用<Component />的JSX语法渲染,不需要克隆。
内容的提问来源于stack exchange,提问作者themegabyte

