最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Rendering a component only after API request is finished React hooks - Stack Overflow

programmeradmin0浏览0评论

I'm getting an error when my chart ponent renders due to its initial state which is an empty array before the API response. It would say something like Cannot read property '0' of undefined which is due to the fact that when the ponent loads, its initial state is, well... an empty array. So I'd like to know if there's a way to make the ponent render only after the API response is received.

Here is the parent ponent:

function InformationPage({
    match: {
        params: { symbol },
    },
}) {

    const [chartData, setChartData] = useState([]); {/*Declaring state*/}

useEffect(() => {  {/*Fetching API response here to set state*/}
    axios
        .get(
            `=${symbol}&resolution=15&from=1572651390&to=1602623478&token=xxxxxxxxx`
        )
        .then((res) => {
            console.log(res.data);
            setChartData(res.data);
        })
        .catch((err) => {
            console.log(err);
        });
}, [symbol]);

return (
    
        <Grid item container xs={12} sm={12} md={6} lg={8}>
            {chartData && <QuoteChart chartData={chartData} iex={iex} />}
        </Grid>
    
   );
}
export Default InformationPage;

Here is the child chart ponent, basically when I do the fetch request from axios it returns an array that will get mapped in the chartRender object. I just need to find a way to render the ponent only AFTER the api request from axios is finished as to not have an error. Any help would be greatly appreciated.

function QuoteChart(props) {
    const classes = useStyles();
    const { chartData } = props;

    const chartRender = chartData.map((chartConfig) => ({
        x: new Date(chartConfig?.t),
        y: [chartConfig?.o, chartConfig?.h, chartConfig?.l, chartConfig?.c],
    }));

    // const chartDataLog = console.log(chartData);
    const config = {
        series: [
            {
                data: [{ chartRender }],
            },
        ],

I'm getting an error when my chart ponent renders due to its initial state which is an empty array before the API response. It would say something like Cannot read property '0' of undefined which is due to the fact that when the ponent loads, its initial state is, well... an empty array. So I'd like to know if there's a way to make the ponent render only after the API response is received.

Here is the parent ponent:

function InformationPage({
    match: {
        params: { symbol },
    },
}) {

    const [chartData, setChartData] = useState([]); {/*Declaring state*/}

useEffect(() => {  {/*Fetching API response here to set state*/}
    axios
        .get(
            `https://finnhub.io/api/v1/stock/candle?symbol=${symbol}&resolution=15&from=1572651390&to=1602623478&token=xxxxxxxxx`
        )
        .then((res) => {
            console.log(res.data);
            setChartData(res.data);
        })
        .catch((err) => {
            console.log(err);
        });
}, [symbol]);

return (
    
        <Grid item container xs={12} sm={12} md={6} lg={8}>
            {chartData && <QuoteChart chartData={chartData} iex={iex} />}
        </Grid>
    
   );
}
export Default InformationPage;

Here is the child chart ponent, basically when I do the fetch request from axios it returns an array that will get mapped in the chartRender object. I just need to find a way to render the ponent only AFTER the api request from axios is finished as to not have an error. Any help would be greatly appreciated.

function QuoteChart(props) {
    const classes = useStyles();
    const { chartData } = props;

    const chartRender = chartData.map((chartConfig) => ({
        x: new Date(chartConfig?.t),
        y: [chartConfig?.o, chartConfig?.h, chartConfig?.l, chartConfig?.c],
    }));

    // const chartDataLog = console.log(chartData);
    const config = {
        series: [
            {
                data: [{ chartRender }],
            },
        ],
Share Improve this question asked Oct 15, 2020 at 12:53 PacholoamitPacholoamit 2656 silver badges18 bronze badges
Add a ment  | 

4 Answers 4

Reset to default 8

Update: According to Finnhub API it's an object that you receive from the API, not an array. This means that charData.length in my previous answer will never be evaluated to true and the child ponent QuoteChart will never get rendered.

I'd suggest the following changes. In your parent ponent, make charData = null initially:

const [chartData, setChartData] = useState(null);

When the API has returned a response and chartData has been assigned a value your child ponent can be rendered:

{chartData && <QuoteChart chartData={chartData} iex={iex} />}

The chart you want to render in the child ponent expects the following input: [{ x: date, y: [O,H,L,C] }]. Because map() can only be called on arrays and chartData is not one, you should navigate to one of the arrays inside the said object, e.g. chartData.t:

const chartRender = chartData.t.map((timestamp, index) => ({
    x: new Date(timestamp),
    y: [chartData.o[index], chartData.h[index], chartData.l[index], chartData.c[index]],
}));

Finally, series.data expects an array, you don't need to additionally wrap it in an object. So this should work:

const config = {
    series: [{
        data: chartRender
    }]
};

You initialize chartData with an empty array, therefore your condition should look like this:

{chartData.length && <QuoteChart chartData={chartData} iex={iex} />}

If you expect the API to return an empty list, I'd remend to set an undefined or null as the initial value of chartData:

const [chartData, setChartData] = useState(null);

In this case you can keep your condition as is.

If I'm not mistaken you can simply use async/await for your problem. So change the useEffect line to

useEffect(async () => {  {/*Fetching API response here to set state*/}

and then

 await axios
    .get(
        `https://finnhub.io/api/v1/stock/candle?symbol=${symbol}&resolution=15&from=1572651390&to=1602623478&token=xxxxxxxxx`
    )

Then your application should wait for the axios to finish fetching

You need to wrap your axios call in an async function and wait there

useEffect(() => {  {/*Fetching API response here to set state*/}
    
   const getInfo = async () => {
       await res = axios
        .get(
            `https://finnhub.io/api/v1/stock/candle?symbol=${symbol}&resolution=15&from=1572651390&to=1602623478&token=xxxxxxxxx`
        )
        console.log(res.data);
        setChartData(res.data);
   }

   getInfo()
}, [symbol]);

The easiest way would require a simple small change to your code:

 {chartData.length && <QuoteChart chartData={chartData} iex={iex} />}

After researching finnhub - I see that the response is not an array. I tested this url:

https://finnhub.io/api/v1/stock/candle?symbol=AAPL&resolution=15&from=1572651390&to=1602623478&token=

The response is an object with a "c" property. Your code should be modified accordingly. For the above link example:

setChartData(res.data.c);
发布评论

评论列表(0)

  1. 暂无评论
ok 不同模板 switch ($forum['model']) { /*case '0': include _include(APP_PATH . 'view/htm/read.htm'); break;*/ default: include _include(theme_load('read', $fid)); break; } } break; case '10': // 主题外链 / thread external link http_location(htmlspecialchars_decode(trim($thread['description']))); break; case '11': // 单页 / single page $attachlist = array(); $imagelist = array(); $thread['filelist'] = array(); $threadlist = NULL; $thread['files'] > 0 and list($attachlist, $imagelist, $thread['filelist']) = well_attach_find_by_tid($tid); $data = data_read_cache($tid); empty($data) and message(-1, lang('data_malformation')); $tidlist = $forum['threads'] ? page_find_by_fid($fid, $page, $pagesize) : NULL; if ($tidlist) { $tidarr = arrlist_values($tidlist, 'tid'); $threadlist = well_thread_find($tidarr, $pagesize); // 按之前tidlist排序 $threadlist = array2_sort_key($threadlist, $tidlist, 'tid'); } $allowpost = forum_access_user($fid, $gid, 'allowpost'); $allowupdate = forum_access_mod($fid, $gid, 'allowupdate'); $allowdelete = forum_access_mod($fid, $gid, 'allowdelete'); $access = array('allowpost' => $allowpost, 'allowupdate' => $allowupdate, 'allowdelete' => $allowdelete); $header['title'] = $thread['subject']; $header['mobile_link'] = $thread['url']; $header['keywords'] = $thread['keyword'] ? $thread['keyword'] : $thread['subject']; $header['description'] = $thread['description'] ? $thread['description'] : $thread['brief']; $_SESSION['fid'] = $fid; if ($ajax) { empty($conf['api_on']) and message(0, lang('closed')); $apilist['header'] = $header; $apilist['extra'] = $extra; $apilist['access'] = $access; $apilist['thread'] = well_thread_safe_info($thread); $apilist['thread_data'] = $data; $apilist['forum'] = $forum; $apilist['imagelist'] = $imagelist; $apilist['filelist'] = $thread['filelist']; $apilist['threadlist'] = $threadlist; message(0, $apilist); } else { include _include(theme_load('single_page', $fid)); } break; default: message(-1, lang('data_malformation')); break; } ?>