简体   繁体   English

在渲染反应钩子之前等待 API 数据

[英]Wait for API data before render react hooks

I make two API call.我打了两个 API 电话。 Data from getAllCampaign api renders but for loadStats It appears React goes ahead to build a table without the data, thus throwing error of Uncaught TypeError: Cannot read property 'data' of undefined Here's what I'm doing.来自getAllCampaign api 的数据呈现,但对于loadStats似乎 React 继续构建一个没有数据的表,因此抛出 Uncaught TypeError 错误:无法读取未定义的属性“数据”这就是我正在做的。

coreapihelpers: coreapihelpers:

export const getAllCampaign = () => {
    return fetch(`https://api.truepush.com/api/v1/listCampaign/1`, {
        method: "GET",
        headers: {
            Authorization: `$TOKEN`,
            "Content-Type": "application/json",
        },
    })
    .then(response => {
        return response.json()
    })
    .catch(err => console.log(err))
}

export const loadStats = async () => {
    const ids = await getAllCampaign()

    const data = Promise.all(
        ids.data.map(async (i) => await (await fetch(`https://api.truepush.com/api/v1/campaignStats/${i.campaignId}`, {
            method: "GET",
            headers: {
                Authorization: ``$TOKEN``,
                "Content-Type": "application/json"
            }
        })).json())
    )
    return data
};

allData output is delayed on console allData output 在控制台上延迟

Full code:完整代码:

import React, {useState, useEffect} from 'react';
import {getAllCampaign, loadStats} from "../helpers/coreapihelpers";

const TableRow = () => {

    const [campaigns, setCampaigns] = useState([]);
    const [stats, setStats] = useState([]);

    const loadAllCampaigns = () => {
        getAllCampaign()
            .then(data => { setCampaigns(data.data) })
            .catch(err => { console.log(err) });
    };

    const loadAllStats = () => {
        loadStats()
            .then(data => { setStats(data) })
            .catch(err => { console.log(err) });
    }

    useEffect(() => {
       loadAllCampaigns();
       loadAllStats();
    }, [])

    const allData = campaigns.map ? campaigns.map((campaign, i) => ({
        ...campaign,
        ...stats[i],
    }))
        : <h1>API LIMIT EXCEEDS</h1>

    return (
        <div className="container">
            <div className="row">
                <div className="col-xs-12">
                    {allData.map ? allData.map((campaigns, index) => (
                        <div className="table-responsive" data-pattern="priority-columns">
                            <table className="table table-bordered table-hover">
                                <thead>
                                <tr>
                                    <th>Sr. No</th>
                                    <th>Campaign Id</th>
                                    <th>Campaign Name</th>
                                    <th>Campaign Status</th>
                                    <th>Reach</th>
                                    <th>Sent</th>
                                    <th>Delivered</th>
                                    <th>Views</th>
                                    <th>Clicks</th>
                                    <th>Unsubscribers</th>
                                </tr>
                                </thead>
                                <tbody>
                                <tr key={index}>
                                    <td>{index + 1}</td>
                                    <td>{campaigns.campaignId}</td>
                                    <td>{campaigns.campaignTitle}</td>
                                    <td>{campaigns.campaignStatus}</td>
                                    <td>{campaigns.data.Reach}</td>
                                    <td>{campaigns.data.Sent}</td>
                                    <td>{campaigns.data.Delivered}</td>
                                    <td>{campaigns.data.Views}</td>
                                    <td>{campaigns.data.Clicks}</td>
                                    <td>{campaigns.data.Unsubscribers}</td>
                                </tr>
                                </tbody>
                            </table>
                        </div>)) : <h1>API Limit Exceeds / API Token Broken</h1>}
                    </div>
                 </div>
            </div>
            );
        }

export default TableRow;

I think the problem is that you should be checking whether state campaigns has been populated, not allData .我认为问题在于您应该检查是否已填充 state campaigns ,而不是allData allData is a variable, not the actual state. allData是一个变量,而不是实际的 state。 Actual state should be used for conditional rendering.实际的 state 应该用于条件渲染。 Try this:尝试这个:

Replace this:替换这个:

allData.map ? allData.map((campaigns, index)

With this:有了这个:

campaigns ? allData.map((campaigns, index)

However, you should create an object for state that contains both campaigns and stats, since you intend to use them as corresponding items.但是,您应该为 state 创建一个 object,其中包含活动和统计信息,因为您打算将它们用作相应的项目。 Or, your database query should return them as one item with some time of join.或者,您的数据库查询应该将它们作为一个项目返回,并有一段时间的加入。

Try this for a client side solution:试试这个作为客户端解决方案:

const [stateObj, setObj] = useState([]);
const campaigns = [];
const stats = [];

const loadAllState = async () => {
    try {
       campaigns = await getAllCampaign();
    } catch (err) {
       console.log(err)
    }

    try {
       stats = await loadStats();
    } catch (err) {
       console.log(err)
    }

    setObj(campaigns.map((campaign, i) => ({
       ...campaign,
       ...stats[i],
  })))
};

useEffect(() => {
   loadAllState();
}, [])

Then:然后:

stateObj ? stateObj.map((campaigns, index)

You should see for allData if it is defined or not like this您应该查看 allData 是否已这样定义

 {allData ? allData.map((campaigns, index) => .......}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM