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

React组件异步获取数组后未更新且读取属性报错问题

React组件异步取数后渲染报错的解决方法

问题描述

我有一个React组件,通过async-await函数从数据库获取对象数组。数据库能正确返回数据(可通过console.log确认),但把数据设置到State后组件没正常更新,还出现属性读取错误。

组件代码

export default function LevelLeaderboard ({ level }) {
  const [leaderboardData, setLeaderboardData] = useState([])

  useEffect(()=>{
    getLeaderBoardData(level)
    .then((data)=>{
      console.log(data)
      setLeaderboardData(data)
    })
  },[level]);

  return (
    <div id="level" className="level-leaderboard">
      <ul>
      <li>{leaderboardData[0]['name']}</li>
      </ul>
    </div>       
  )
}

错误信息

LevelLeaderboard.js:19 Uncaught TypeError: Cannot read properties of undefined (reading '0')
at LevelLeaderboard (LevelLeaderboard.js:19:1)
at renderWithHooks (react-dom.development.js:16305:1)
at mountIndeterminateComponent (react-dom.development.js:20074:1)
at beginWork (react-dom.development.js:21587:1)
at HTMLUnknownElement.callCallback (react-dom.development.js:4164:1)
at Object.invokeGuardedCallbackDev (react-dom.development.js:4213:1)
at invokeGuardedCallback (react-dom.development.js:4277:1)
at beginWork$1 (react-dom.development.js:27451:1)
at performUnitOfWork (react-dom.development.js:26557:1)
at workLoopSync (react-dom.development.js:26466:1)

异步函数代码

export async function getLeaderBoardData(level, handleData){
  const querySnapshot = await getDocs(collection(leaderboard, level));
  let tempArr = [];
  querySnapshot.forEach((doc) => {
    tempArr.push(doc.data())
  });
  return tempArr;
}

问题根源

错误的核心是初始渲染时数据还未加载完成:

  • 组件挂载时,leaderboardData的初始值是空数组[]
  • 此时直接访问leaderboardData[0]['name'],leaderboardData[0]会返回undefined,再读取name属性就触发TypeError
  • 虽然异步请求完成后会更新state,但初始渲染的错误已经导致组件崩溃

解决方法

1. 条件渲染(推荐)

先判断数组是否有数据,再渲染对应内容,同时可以添加加载提示:

export default function LevelLeaderboard ({ level }) {
  const [leaderboardData, setLeaderboardData] = useState([])

  useEffect(()=>{
    getLeaderBoardData(level)
    .then((data)=>{
      console.log(data)
      setLeaderboardData(data)
    })
  },[level]);

  return (
    <div id="level" className="level-leaderboard">
      <ul>
        {leaderboardData.length > 0 ? (
          <li>{leaderboardData[0]['name']}</li>
        ) : (
          <li>加载中...</li>
        )}
      </ul>
    </div>       
  )
}

2. 使用可选链操作符(?.)

通过?.语法避免访问undefined的属性,同时可以设置默认值:

export default function LevelLeaderboard ({ level }) {
  const [leaderboardData, setLeaderboardData] = useState([])

  useEffect(()=>{
    getLeaderBoardData(level)
    .then((data)=>{
      console.log(data)
      setLeaderboardData(data)
    })
  },[level]);

  return (
    <div id="level" className="level-leaderboard">
      <ul>
        <li>{leaderboardData[0]?.['name'] || '加载中...'}</li>
      </ul>
    </div>       
  )
}

3. 提前处理空数组边界

如果数据库可能返回空数组,可以在组件顶部提前判断并返回默认内容:

export default function LevelLeaderboard ({ level }) {
  const [leaderboardData, setLeaderboardData] = useState([])

  useEffect(()=>{
    getLeaderBoardData(level)
    .then((data)=>{
      console.log(data)
      setLeaderboardData(data)
    })
  },[level]);

  if (leaderboardData.length === 0) {
    return <div className="level-leaderboard">暂无数据</div>
  }

  return (
    <div id="level" className="level-leaderboard">
      <ul>
        <li>{leaderboardData[0]['name']}</li>
      </ul>
    </div>       
  )
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:30:54