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

React Native传递SVG图标作为Props时遭遇JSX类型错误

React Native传递SVG图标Props报错解决

问题描述

在React Native组件中尝试将SVG图标作为props传递时,遇到错误:

JSX element type 'Icon' does not have any construct or call signatures.

相关代码

子组件代码

type Props = {
  price: string;
  Icon: JSX.Element;
};

const MapPin = ({ price, Icon }: Props) => (
  <View style={styles.bubbleContainer}>
    <View style={styles.bubbleContent}>
      <Icon />
      <Text style={styles.bubblePrice}>{price}</Text>
    </View>
    <View style={styles.bubbleArrow} />
  </View>
);

父组件代码

import BPIcon from '../../../../assets/images/maps/bp_icon.svg';
import ShellIcon from '../../../../assets/images/maps/shell_icon.svg';
import TescoIcon from '../../../../assets/images/maps/tesco_icon.svg';
import TexacoIcon from '../../../../assets/images/maps/texaco_icon.svg';
import sampleData from '../../sampleData';

const MapComponent = () => {
  const renderIcon = (type: string) => {
    switch (type) {
      case 'bp':
        return <BPIcon />;
      case 'shell':
        return <ShellIcon />;
      case 'texaco':
        return <TexacoIcon />;
      case 'tesco':
        return <TescoIcon />;
    }
  };

  return (
    <MapView
      ...>
      {sampleData.map((marker, i) => {
        console.log(marker.icon);
        const Icon = renderIcon(marker.icon);
        console.log(Icon);
        return (
          <Marker key={i} coordinate={marker.coordinates}>
            <MapPin price={marker.price} Icon={Icon} />
          </Marker>
        );
      })}
    </MapView>
  );
};

示例数据代码

const sampleData = [
  {
    name: 'test station',
    icon: 'shell',
    price: '15.00p',
    coordinates: {
      latitude: 52.56504897473243,
      longitude: -1.9835459043698045,
    },
  },
  {
    name: 'test station',
    icon: 'bp',
    price: '10.00p',
    coordinates: {
      latitude: 52.564655445785036,
      longitude: -1.9895132194946084,
    },
  },
  {
    name: 'test station',
    icon: 'texaco',
    price: '12.00p',
    coordinates: {
      latitude: 52.56675992926686,
      longitude: -1.9925531724706291,
    },
  },
  {
    name: 'test station',
    icon: 'tesco',
    price: '12.00p',
    coordinates: {
      latitude: 52.56464922306586,
      longitude: -1.9913983181615922,
    },
  },
  {
    name: 'test station',
    icon: 'texaco',
    price: '12.00p',
    coordinates: {
      latitude: 52.5653679624953,
      longitude: -1.9930410479235137,
    },
  },
  {
    name: 'test station',
    icon: 'shell',
    price: '12.00p',
    coordinates: {
      latitude: 52.563723048919684,
      longitude: -1.9902561905426908,
    },
  },
];

错误原因

你在子组件Props里把Icon定义为JSX.Element类型,这代表已经渲染完成的元素实例;但父组件传递的是<BPIcon />这类已创建的元素,子组件却试图把它当作可调用的组件使用(<Icon />)——两者逻辑矛盾,因此TypeScript抛出错误。

修复方案

两种可行方案任选其一:

方案一:直接传递已渲染元素,子组件直接渲染

适合不需要给图标传额外props的场景:

  1. 修改子组件的Props和使用方式:
type Props = {
  price: string;
  icon: JSX.Element; // 改名贴合语义,明确是元素而非组件
};

const MapPin = ({ price, icon }: Props) => (
  <View style={styles.bubbleContainer}>
    <View style={styles.bubbleContent}>
      {icon} {/* 直接渲染元素,无需加括号 */}
      <Text style={styles.bubblePrice}>{price}</Text>
    </View>
    <View style={styles.bubbleArrow} />
  </View>
);
  1. 父组件传递时调整参数名:
// MapComponent中的map循环部分
{sampleData.map((marker, i) => {
  const icon = renderIcon(marker.icon);
  return (
    <Marker key={i} coordinate={marker.coordinates}>
      <MapPin price={marker.price} icon={icon} />
    </Marker>
  );
})}

方案二:传递组件本身,子组件调用渲染

更灵活,后续可方便给图标传size、color等props:

  1. 修改父组件的renderIcon,返回组件而非已渲染元素:
const renderIcon = (type: string) => {
  switch (type) {
    case 'bp':
      return BPIcon; // 不要加<></>,直接返回组件本身
    case 'shell':
      return ShellIcon;
    case 'texaco':
      return TexacoIcon;
    case 'tesco':
      return TescoIcon;
    default:
      return null; // 增加默认返回,避免undefined
  }
};
  1. 修改子组件的Props类型,使用React的ComponentType:
import type { ComponentType } from 'react';

type Props = {
  price: string;
  Icon: ComponentType; // 表示这是一个React组件类型
};

const MapPin = ({ price, Icon }: Props) => (
  <View style={styles.bubbleContainer}>
    <View style={styles.bubbleContent}>
      <Icon /> {/* 现在可正常调用组件 */}
      <Text style={styles.bubblePrice}>{price}</Text>
    </View>
    <View style={styles.bubbleArrow} />
  </View>
);
  1. 父组件传递逻辑无需修改,保持Icon={renderIcon(marker.icon)}即可。

内容的提问来源于stack exchange,提问作者Bomber

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 18:14:53