开发者问题收集

未捕获(在承诺中)TypeError:data.map不是一个函数(React 使用 axios 从 ASP.NET API 获取数据)

2019-08-16
1709

我使用 ASP.NET 创建了一个 API,并且我有一个运行 React 的网站。我想使用 Axios 显示从 API 到 React 的获取请求检索的数据。该网站有一种使用两个 cookie 的身份验证方法。我可以让 Axios 从 https://jsonplaceholder.typicode.com/users 获取数据,但是当我使用相同的代码时,我收到错误:Uncaught (in promise) TypeError: data.map is not a function.

我已尝试如上所述使用占位符,并且工作正常,但似乎无法从我的 API 获取数据,这让我相信问题出在 cookie 上。我也尝试了几次 Google 搜索,结果显示我应该包含 withCredentials: true,但这没有起到作用。

这是我的 API 中的函数:

public JsonResult YearlyManagersJSON(int year = 0)
{
    if (year < 2000 || year > DateTime.Today.Year)
        year = DateTime.Today.Year;

    var startDate = new DateTime(year, 1, 1);
    var endDate = new DateTime(year + 1, 1, 1);

    var bonds = this.getOverviewData(ReportType.BONDS, startDate, endDate);
    var bondsSum = bonds.Sum(m => m.Aggregate);

    var viewData = new TopLeadManagerViewData
        {
            Title = String.Format("Top Managers in {0}", startDate.Year),
            Currency = SiteHelper.getCurrencyToUse(),
            Bonds = Enumerable.Select(bonds, m => new ManagerSummary()
                {
                    NumberOfIssues = (int)m.Aggregate2,
                    TotalAmount = m.Aggregate * 1000000,
                    Name = m.Group.ToString(),
                    Share = 100.0m * m.Aggregate / bondsSum
                }),
        };

        return this.Json(viewData, JsonRequestBehavior.AllowGet);
}

这将返回一个 JSON,我已使用 Postman 检查过。然后我尝试使用 axios 访问数据。

state = {
    yearlyBonds: []
}

componentDidMount() {
    axios.get(
        'http://localhost/Stamdata.Web/LeagueTable/YearlyManagersJSON',
        { withCredentials: true }
    )
    .then(res => {
        const yearlyBonds = res.data;
        this.setState({ yearlyBonds });
    })
}

render() {
    return (
        // Tags removed for simplicity
        <ListTable data={this.state.yearlyBonds.Bonds} />

然后将数据传递到组件中

function ListTable(props) {
        const { classes, header, data } = props;
        return(
            // Tags removed for simplicity
                        <TableBody>
                            {data.map((x, i) => {
                                return(
                                    <TableRow key={i}>
                                        <TableCell scope="row">{x.Name}</TableCell>
                                        <TableCell scope="row">{x.TotalAmount}</TableCell>
                                        <TableCell scope="row">{x.Share}</TableCell>
                                        <TableCell scope="row">{x.NumberOfIssues}</TableCell>
                                    </TableRow>
                                )
                            })}
                        </TableBody>

因此,这会返回错误

"Uncaught (in promise) TypeError: data.map is not a function", which I would like to have display the data retrieved.

3个回答

您的初始状态是,

yearlyBonds: []

当组件首次呈现时,它采用初始状态。最初,您有一个空数组。因此对空数组进行迭代会给出错误。

您可以有条件地添加您的组件,例如,

{ this.state.yearlyBonds.Bonds && <ListTable data={this.state.yearlyBonds.Bonds} />}
ravibagul91
2019-08-16

Note that, componentDidMount gets called after 1st render (when component mounts into DOM).

您有以下组件工作流程 -

  1. 在第一次渲染期间,您有一个状态 -

    state = { annualBonds: []

    在渲染函数中,您想要传递 Bonds 关键数据,该数据在初始状态下不存在,直到进行 API 调用并且状态具有 Bonds 数据。

  2. 由于 this.state.yearlyBonds.Bonds 在初始渲染期间未定义,因此您无法在 undefined 对象上调用 map 方法。 这就是您看到该错误的原因

Now to fix this, there are quite a few methods:

方法 1(最简单):

像这样更新您的状态 -

state = {
    yearlyBonds: {
       bonds: []
    }
}

您的渲染将在没有任何其他更改的情况下工作。

方法 2(中等):

更新您的函数以接受具有 data

function ListTable({ classes, header, data=[] }) {
// rest of the code goes here
默认值的解结构化 props>

方法 3:(API 调用的正确方法):

在您的组件状态中添加 isLoading 标志。我们将使用它来显示一个后备的“正在加载...”UI,直到我们从 API 获得数据。

state = {
    yearlyBonds: [],
    isLoading: false,
}

在进行 API 调用之前,通过将“isLoading”设置为 true 来更新您的状态。

componentDidMount() {
    // update state
    this.setState({ isLoading: true });
    axios.get(
        'http://localhost/Stamdata.Web/LeagueTable/YearlyManagersJSON',
        { withCredentials: true }
    )
    .then(res => {
        const yearlyBonds = res.data;
        // set isLoading to false, as data is received
        this.setState({ yearlyBonds, isLoading: false });
    })
}

最后在渲染方法中,读取 isLoading 状态并渲染一个后备。

// rest of the code

render() {
     if (this.state.isLoading) {
        return <div> Loading ... </div>;

    // when data is available
    return (
        // Tags removed for simplicity
        <ListTable data={this.state.yearlyBonds.Bonds} />

pritam
2019-08-16

发生这种情况是因为您正在迭代一个空数组。

Víctor Omar Vento Hernández
2022-07-22