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

React音乐播放器洗牌功能报错:更新共享state时无法读取title

音乐播放器洗牌功能报错修复

场景说明

我正在开发一款音乐播放器,组件结构如下:

  • A:Home.jsx(首页组件)
  • B:ChartSongs.jsx(榜单歌曲组件)
  • C:AudioPlayer.jsx(音频播放器组件)

在Home组件中,我通过接口获取了歌曲数组chartData,并将其作为props传递给ChartSongs组件:

// chartData是从接口获取的歌曲数组
const songTitleEl = chartData.map((data, i) => (
  <ChartSongs 
    key={data.key} 
    title={data.title} 
    artiste={data.subtitle} 
    coverarts={data.images?.coverart} 
    index={i}
  />
))

我使用Context API在组件间共享chartData,并在AudioPlayer组件中实现了Fisher-Yates洗牌算法用于打乱歌曲顺序:

function shuffle(arr){
  for (let i = arr.length; i > 0; i--){
    const j = Math.floor(Math.random() * (i + 1));
    const temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp; 
  }
  return arr;
}

随后编写了更新状态的函数:

function playShuffle(){
  setChartData(shuffle(chartData))
}

报错信息

调用playShuffle()时出现如下错误:

Uncaught TypeError: Cannot read properties of undefined (reading 'title')
    at Home.jsx:74:44
    at Array.map (<anonymous>)
    at Home (Home.jsx:73:33)
    at renderWithHooks (react-dom.development.js:16305:18)
    at updateFunctionComponent (react-dom.development.js:19588:20)
    at beginWork (react-dom.development.js:21601:16)
    at beginWork$1 (react-dom.development.js:27426:14)
    at performUnitOfWork (react-dom.development.js:26557:12)
    at workLoopSync (react-dom.development.js:26466:5)
    at renderRootSync (react-dom.development.js:26434:7)

chartData数组的每个元素包含title、subtitle、images等字段。

问题原因

  1. Fisher-Yates算法实现错误:循环起始值设为arr.length,但数组的最大有效索引是arr.length - 1,此时arr[i]为undefined,交换后数组中会混入undefined元素,导致map遍历访问data.title时出错。
  2. 直接修改原数组:React状态是不可变的,直接修改原数组会导致状态更新异常,且可能引发不可预测的渲染问题。

解决方案

1. 修正Fisher-Yates洗牌算法

调整循环起始值和随机索引范围,同时复制原数组避免修改原状态:

function shuffle(arr) {
  // 复制原数组,不直接修改状态中的原始数据
  const newArr = [...arr];
  // 从最后一个有效索引开始循环
  for (let i = newArr.length - 1; i > 0; i--) {
    // 生成0到i(包含i)的随机索引
    const j = Math.floor(Math.random() * (i + 1));
    // 解构赋值交换元素
    [newArr[i], newArr[j]] = [newArr[j], newArr[i]];
  }
  return newArr;
}

2. 正确更新状态

调用洗牌函数时,直接传入原数组即可(洗牌函数内部已做拷贝):

function playShuffle() {
  setChartData(shuffle(chartData));
}

3. 可选:添加空值保护

在Home组件的map遍历中增加空值判断,避免因数组元素异常导致报错:

const songTitleEl = chartData.map((data, i) => {
  if (!data) return null; // 跳过undefined元素
  return (
    <ChartSongs 
      key={data.key} 
      title={data.title} 
      artiste={data.subtitle} 
      coverarts={data.images?.coverart} 
      index={i}
    />
  )
})

修改后洗牌功能可正常运行,不会再出现undefined元素导致的报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 05:20:42