React项目fetch请求异常及读取gameArray属性报错求助
咱们一步步拆解你的问题,先解决最核心的几个关键点:
1. 表单提交直接中断了Fetch请求(最关键的根因)
你用的是<button type="submit">,点击后浏览器会默认触发表单的提交刷新页面行为。这就导致你的fetchHaloMatches函数刚执行到fetch步骤,页面就直接刷新了——所以网络面板看不到请求、断点被跳过,都是因为页面重新加载后,之前的代码上下文直接消失了。
修复方法:在点击事件里阻止默认行为:
async fetchHaloMatches(e) { e.preventDefault(); // 阻止表单默认提交刷新页面 // 剩下的原有逻辑不变 }
确保按钮的onClick正确传递事件参数:
<button type="submit" onClick={this.fetchHaloMatches}>Search</button>
2. Props传递名称不匹配,导致gameArray未定义错误
在ButtonMatches的render中,你传给MatchList的props是recentMatches={this.data},但在MatchList里却尝试访问this.props.data.gameArray——这里的props名称是recentMatches,不是data!所以this.props.data是undefined,自然无法读取gameArray。
修复方法:统一props名称即可,比如修改MatchList的代码:
// MatchList.js的render方法 return( <MatchEntry game={this.props.recentMatches.gameArray[i]} category={this.props.recentMatches.categoryArray[i]} map={this.props.recentMatches.mapArray[i]} victory={this.props.recentMatches.victoryArray[i]} kills={this.props.recentMatches.killsArray[i]} deaths={this.props.recentMatches.deathsArray[i]} /> );
3. 使用实例属性this.data而非State,导致组件无法响应数据更新
你把gameArray等数据存在了实例属性this.data里,但React只会在state或props变化时触发组件重新渲染。即使fetch成功填充了this.data,组件也不会自动刷新,因为React完全不知道这些数据发生了变化。
修复方法:把这些数组移到组件的state中:
constructor(props) { super(props); this.state = { totalKD: 0, totalWL: 0, gameArray : [], categoryArray : [], mapArray : [], victoryArray : [], killsArray : [], deathsArray : [], }; this.fetchHaloMatches = this.fetchHaloMatches.bind(this); }
然后在fetch的回调里用this.setState更新数据:
.then(res => { let totalKills = 0, totalDeaths = 0, totalVictories = 0, totalLosses = 0; // 先创建新数组,避免直接修改state const gameArray = []; const categoryArray = []; const mapArray = []; const victoryArray = []; const killsArray = []; const deathsArray = []; for (let i=0; i< res.data.length; i++) { const match = res.data[i]; victoryArray[i] = match.victory; victoryArray[i] ? totalVictories++ : totalLosses++ killsArray[i] = match.stats.kills; totalKills += killsArray[i]; deathsArray[i] = match.stats.deaths; totalDeaths += deathsArray[i]; mapArray[i] = match.details.map.name; categoryArray[i] = match.details.category.name; gameArray[i] = match.details.engine.name; } const totalKD = totalKills / totalDeaths; const totalWL = totalVictories / totalLosses; this.setState({ totalKD, totalWL, gameArray, categoryArray, mapArray, victoryArray, killsArray, deathsArray, }); })
最后在render里传递state给MatchList:
<MatchList recentMatches={ this.state } />
4. 额外优化:添加加载状态与错误处理
建议在state里添加isLoading状态,避免在数据加载中渲染错误内容,同时完善fetch的错误处理:
// constructor中添加 this.state = { // ...其他状态 isLoading: false, }; // 修改fetchHaloMatches为async/await风格,更易读 async fetchHaloMatches(e) { e.preventDefault(); this.setState({ isLoading: true }); try { const gamertag = document.getElementById("search-recent-matches").value; const url3 = `https://cryptum.halodotapi.com/games/hmcc/stats/players/${gamertag}/recent-matches?page=1`; const response = await fetch(url3, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Cryptum-API-Version': '2.3-alpha', 'Authorization': 'Cryptum-Token HOePLO1QYGIbelnxcQSq9y6ZXbX6MWahQZlQq1zaXQqHXEd4mWyOZ6YgaijjdCyB' } }); if (!response.ok) { throw new Error(`请求失败,状态码:${response.status}`); } const res = await response.json(); // ...处理数据并更新state this.setState({ isLoading: false }); } catch (error) { console.log("There was an error: " + error); this.setState({ isLoading: false }); } }
然后在render里判断加载状态:
render() { const { totalKD, totalWL, isLoading } = this.state; if (isLoading) { return <div>加载中...</div>; } if (totalKD === 0 && totalWL === 0) { // 初始状态,显示表单 return ( <div> <form> <label htmlFor="gamertag">Xbox Live Gamertag:</label> <input type="search" id="search-recent-matches" name="Gamertag" placeholder="Enter a Gamertag..."></input> <button type="submit" onClick={ this.fetchHaloMatches } >Search</button> </form> </div> ); } else { // 有数据,显示表单+MatchList return ( <div> <div> <form> <label htmlFor="gamertag">Xbox Live Gamertag:</label> <input type="search" id="search-recent-matches" name="Gamertag" placeholder="Enter a Gamertag..."></input> <button type="submit" onClick={ this.fetchHaloMatches } >Search</button> </form> </div> <MatchList recentMatches={ this.state } /> </div> ); } }
内容的提问来源于stack exchange,提问作者GD1

