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

React组件因竞态条件致toUpperCase报错的解决方案求助

解决React Icon组件中toUpperCase()的undefined错误

核心原因

虽然你给icon声明了PropTypes.string.isRequired,但实际渲染时icon仍可能为undefined——大概率是chartMarkets数组初始状态包含undefined项,或者异步加载数据时组件先完成了初始渲染,导致type值未就绪。

可行解决方案

1. 组件内部添加防御性检查(最直接)

直接在Icon组件里对icon做类型校验和兜底,避免直接调用方法:

const Icon = (props) => {
  const { icon, className } = props;
  // 确保只有字符串类型才调用toUpperCase,否则兜底为空
  const iconText = typeof icon === 'string' ? icon.toUpperCase() : '';

  return (
    <div className={`icon-32 ${className}`} style={{ backgroundImage: `url('data:image/svg+xml;utf-8,<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><style>.text {font-family: sans-serif; font-size: 10px; fill:%23FFF;}</style><circle class="cls-1" cx="16" cy="16" r="16" fill="%231d5baa"/><text x="50%" y="63%" text-anchor="middle" class="text">${iconText}</text></svg>')` }}>
      {/* 只有icon有效时才渲染内层图标,避免无效请求 */}
      {typeof icon === 'string' && icon && (
        <div className={`icon-32  ${className}`} style={{ backgroundImage: `url(/static/images/assets/icons/svg/color/${icon}.svg)` }} />
      )}
    </div>
  );
};

2. 过滤数据源中的无效项

检查chartMarkets数组,确保所有type都是有效字符串,在map前过滤掉无效值:

const renderMenuItems = () => {
  // 过滤掉undefined、null、空字符串等无效项
  const validMarkets = chartMarkets.filter(type => typeof type === 'string' && type.trim());
  return validMarkets.map((type) => {
    return (
      <MenuItem key={type} value={type} onClick={event => handleSelection(event)}>
        <Icon className={classes.menuItemImage} icon={type} />
        <Typography variant="body1">{type}</Typography>
      </MenuItem>
    );
  });
};

注意:别忘了给map的元素加key属性,符合React规范。

3. 给icon添加临时默认值(适配异步场景)

如果chartMarkets是异步加载的,初始状态可能为空或未定义,可以在父组件渲染前加判断,避免提前渲染Icon:

const renderMenuItems = () => {
  // 数据未就绪时返回加载状态或空
  if (!chartMarkets || chartMarkets.length === 0) return null;
  
  return chartMarkets.map((type) => {
    return (
      <MenuItem key={type} value={type} onClick={event => handleSelection(event)}>
        <Icon className={classes.menuItemImage} icon={type || 'default-icon'} />
        <Typography variant="body1">{type || '加载中'}</Typography>
      </MenuItem>
    );
  });
};

这里的default-icon需要你有对应的默认图标文件,或者用空字符串兜底(但要确保组件能正常渲染)。

为什么之前的方法无效?

  • 设置icon默认空字符串:你是在defaultProps里没设icon的默认值(因为标了isRequired),即使设了,空字符串调用toUpperCase()不会报错,但图标路径会变成/.svg,导致无效请求,所以图标不显示。
  • icon={type && type}:如果type是undefined,结果还是undefined,无法解决问题;如果type是空字符串,会传false,同样不符合string类型要求。
  • useEffect:组件渲染时会先执行JSX里的代码,useEffect是在渲染完成后才触发,所以无法拦截渲染时的toUpperCase()调用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 22:09:35