TypeError:无法获取且无法读取未定义的属性

unhi4e5o  于 2022-10-15  发布在  React
关注(0)|答案(2)|浏览(363)

我正在处理一个Reaction项目,而我的Fetch()函数表现得很奇怪。在我以前使用它时,它工作得非常好;现在我试图获取一个不同的URL(相同的域),并在请求中使用相同的头,该函数的行为很奇怪。我尝试做的基本上是检索包含一些数据的JSON,将其存储在组件的属性中,然后呈现它。在完全相同的URL和完全相同的头上使用Postman,我完全能够很好地接收这样的响应,但在VisualStudio中,我得到的错误是:

There was an error: TypeError: Failed to fetch

以及:

The above error occurred in the <MatchList> component:

    at MatchList (http://localhost:3000/static/js/bundle.js:814:5)
    at div
    at ButtonMatches (http://localhost:3000/static/js/bundle.js:258:5)
    at div
    at App

Consider adding an error boundary to your tree to customize error handling behavior.
Visit https://reactjs.org/link/error-boundaries to learn more about error boundaries.
node_modules/react-dom/cjs/react-dom.development.js:20085
There was an error: TypeError: Cannot read properties of undefined (reading 'gameArray')
src/components/ButtonMatches.js:75

这是组件“ButtonMatches.js”,它有一个在URL调用Fetch的方法:

import React from 'react';
import reactDom from 'react-dom';
// import { MapList } from './MapList';
import { MatchList } from './MatchList';

export class ButtonMatches extends React.Component
{

    constructor(props)
    {
        super(props);

        this.state = { totalKD: 0, totalWL: 0 };

        this.data = {  

            gameArray : [],
            categoryArray : [],
            mapArray : [],
            victoryArray : [],
            killsArray : [],
            deathsArray : [],
        };

        this.fetchHaloMatches = this.fetchHaloMatches.bind(this);
    }

    async fetchHaloMatches()  
    {
        const gamertag = document.getElementById("search-recent-matches").value; // gamertag should be the string 'giafra'.

        const url1 = 'https://cryptum.halodotapi.com/games/hmcc/stats/players/'   
        const url2 = url1 + gamertag;  // url1 + 'giafra'                                           
        const url3 = `${url2}/recent-matches?page=1`;  // '.../giafra/recent-matches?page=1

        fetch(url3, {
            "method": 'GET',
            "headers": {
                        'Content-Type': 'application/json',
                        'Cryptum-API-Version': '2.3-alpha',
                        'Authorization': 'Cryptum-Token HOePLO1QYGIbelnxcQSq9y6ZXbX6MWahQZlQq1zaXQqHXEd4mWyOZ6YgaijjdCyB'
                     }
        })
        .then(response =>      
            response.json())   
        .then(res => {   

            let totalKills = 0, totalDeaths = 0, totalVictories = 0, totalLosses = 0;
            for (let i=0; i< res.data.length; i++)
            {

                this.data.victoryArray[i] = res.data[i].victory;
                this.data.victoryArray[i] ? totalVictories++ : totalLosses++ 

                this.data.killsArray[i] = res.data[i].stats.kills;
                totalKills += this.data.killsArray[i];

                this.data.deathsArray[i] = res.data[i].stats.deaths;
                totalDeaths += this.data.deathsArray[i];

                this.data.mapArray[i] = res.data[i].details.map.name;
                this.data.categoryArray[i] = res.data[i].details.category.name;
                this.data.gameArray[i] = res.data[i].details.engine.name;

            }

            const totalKD = (totalKills / totalDeaths), totalWL = (totalVictories / totalLosses);

            this.setState(({  .
                totalKD : totalKD,
                totalWL : totalWL 
            })); 
        })  
        .catch(error => {   
            console.log("There was an error: " + error);
        });
    }

    render()
    {
        if ((this.state.totalKD || this.state.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  
        {
            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.data } />
                </div> 
            );
        }

    }

}

这是组件MatchList.js:

import React from "react";
import { MatchEntry } from './MatchEntry';

export class MatchList extends React.Component  {
    constructor(props)
    {
        super(props);

    }

    render()
    {
        for (let i=0; i< 1; i++)  
        {
            return(

              <MatchEntry game={this.props.data.gameArray[i]}  
                          category={this.props.data.categoryArray[i]} 
                          map={this.props.data.mapArray[i]}
                          victory={this.props.data.victoryArray[i]} 
                          kills={this.props.data.killsArray[i]} 
                          deaths={this.props.data.deathsArray[i]} 
              />
            );
        }
    }

}

然而,我相信在MatchList组件中发生的“无法读取未定义的属性(正在读取‘gameArray’)”被抛出,只是因为ButtonMatches组件中的MatchList的条件呈现确实由于某种原因而被触发,传递了一个未定义的道具,因为该道具依赖于fetch()方法的正确执行以及由此产生的请求数据的正确存储。因为在调试时,fetch()方法中的任何断点都会被忽略,在执行fetch()之后,网络请求会从Chrome Developer Tools的Network选项卡中消失(所以我不能确定它是否真的失败了)。

mrwjdhj3

mrwjdhj31#

找到了解决这个问题的办法。幕后发生的事情是,由于与提交表格相关的默认事件,当点击“提交”按钮时,网页正在刷新。这就是为什么我的网络请求在Chrome Dev工具的网络选项卡中“消失”了。
我通过返回以下内容继续编辑该表单的呈现:

<div>
    <form onSubmit={(event) => { event.preventDefault(); } }>
        <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>

如您所见,我必须调用.preventDefault()方法。由于现在不推荐使用window.Event,我发现onSubmit属性返回与提交相关联的事件(类事件)。然后,我可以对该特定事件调用.preventDefault()方法,从而阻止刷新。记住将提交按钮声明为type="submit",否则这将不起作用。

neskvpey

neskvpey2#

您需要向您的函数中添加预防默认方法。简单地说,不是添加按钮而是单击方法,而是添加表单方法,该方法可以在提交时执行您希望的操作,从而使代码更简洁;例如

async fetchHaloMatches (e) {
    e.preventDefault();
     .
     .
     .
}

<div>
    <form onSubmit={this.fethcHaloMatches}>
        <label htmlFor="gamertag">Xbox Live Gamertag:</label>
        <input type="search" id="search-recent-matches" name="Gamertag" placeholder="Enter a Gamertag..."></input>
        <button type="submit">Search</button>
    </form>
</div>

相关问题