You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中useEffect执行顺序问题:API数据未加载完成无法复用

React中useEffect依赖数据未就绪的解决方案

你的核心问题是第二个useEffect的依赖数组为空,仅在组件挂载时执行一次,此时第一个useEffect的API请求还未完成(耗时8秒),blueCardData还是初始值,isLoading也未更新,导致无法获取有效数据。此外代码中还有两处细节问题:

  • blueCardData初始设为数组[],但API返回的是对象(你后续访问blueCardData.today_revenue等属性),类型不匹配可能引发报错
  • 图表数据处理逻辑错误:arr3始终为空,arr4同时存入时间和数值,导致图表的labels和data完全不符合预期

方案1:修正useEffect依赖,确保数据就绪后执行

将第二个useEffect的依赖数组改为[blueCardData, isLoading],这样每当blueCardData或isLoading更新时,都会重新执行该逻辑,保证数据就绪后再处理图表数据。同时修正数组处理逻辑和初始状态:

import React, { useState, useEffect } from "react";
import { Col, Container, Row } from "react-bootstrap";
import Bluecard from "../../components/bluecard/Bluecard";
import Linechart from "../../charts/linechart/Linechart";
import Solar_1 from "../../assets/images/Solar_1.png";
import Solar_2 from "../../assets/images/Solar_2.png";
import Solar_3 from "../../assets/images/Solar_3.png";
import Solar_4 from "../../assets/images/Solar_4.png";
import Solar_5 from "../../assets/images/Solar_5.png";
import Solar_6 from "../../assets/images/Solar_6.png";
import Solar_7 from "../../assets/images/Solar_7.png";
import Solar_8 from "../../assets/images/Solar_8.png";

function Solarcopy() {
    const [isLoading, setIsLoading] = useState(true);
    // 初始设为null,避免对象属性访问报错
    const [blueCardData, setBlueCardData] = useState(null);
    const [lineData, setLineData] = useState({
        labels: ["Jan", "Feb", "Mar", "Apr", "May", "Jun"],
        datasets: [
            {
                label: "Users Gained",
                data: [10, 20, 30, 10, 15, 30],
                backgroundColor: [
                    "rgba(75,192,192,1)",
                    "#ecf0f1",
                    "#50AF95",
                    "#f3ba2f",
                    "#2a71d0",
                ],
                borderColor: "black",
                borderWidth: 2,
                fill: true,
            },
        ],
    });

    // 获取API数据,增加错误处理
    useEffect(() => {
        fetch("http://192.168.18.21:8000/performance/solar-overview/")
            .then((response) => {
                if (!response.ok) throw new Error("请求失败");
                return response.json();
            })
            .then((dataValues) => {
                setBlueCardData(dataValues);
                setIsLoading(false);
            })
            .catch((err) => {
                console.error(err);
                setIsLoading(false); // 即使失败也停止加载状态
            });
    }, []);

    // 处理图表数据,依赖blueCardData和isLoading
    useEffect(() => {
        // 数据未就绪时直接返回
        if (isLoading || !blueCardData?.pr_hourly) return;

        const labels = blueCardData.pr_hourly.time;
        const data = blueCardData.pr_hourly.pr_hourly;

        setLineData({
            labels,
            datasets: [
                {
                    label: "Values",
                    data,
                    backgroundColor: [
                        "rgba(75,192,192,1)",
                        "#ecf0f1",
                        "#50AF95",
                        "#f3ba2f",
                        "#2a71d0",
                    ],
                    borderColor: "black",
                    borderWidth: 2,
                    fill: true,
                },
            ],
        });
    }, [blueCardData, isLoading]);

    if (isLoading) {
        return <p>Loading Data</p>;
    }

    // 数据加载完成但blueCardData为空时的兜底
    if (!blueCardData) {
        return <p>数据加载失败</p>;
    }

    return (
        <>
            <section>
                <Container fluid>
                    <Row>
                        <Col lg={6}>
                            <Row>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.today_revenue}
                                        spanText="PKR"
                                        text="Today's Revenue"
                                        image={Solar_1}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.cuf}
                                        spanText="%"
                                        text="CUF"
                                        image={Solar_2}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.total_yield}
                                        spanText="KWH"
                                        text="Today's Yield"
                                        image={Solar_3}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.cuf}
                                        spanText="%"
                                        text="CUF"
                                        image={Solar_4}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.system_size}
                                        spanText="kW"
                                        text="System Size"
                                        image={Solar_5}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.inverters}
                                        spanText=""
                                        text="Number Of Inverters"
                                        image={Solar_6}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.performance_ratio}
                                        spanText="%"
                                        text="Performance Ratio"
                                        image={Solar_7}
                                    />
                                </Col>
                                <Col xl={6} className="mt-3">
                                    <Bluecard
                                        heading={blueCardData.tc_performance_ratio}
                                        spanText="%"
                                        text="TCPR"
                                        image={Solar_8}
                                    />
                                </Col>
                            </Row>
                        </Col>
                    </Row>
                </Container>
            </section>
            <section className="mt-lg-5 mt-5">
                <Container fluid>
                    <Row>
                        <Col lg={6}>
                            <Linechart chartData={lineData} />
                        </Col>
                    </Row>
                </Container>
            </section>
        </>
    );
}

export default Solarcopy;

方案2:合并useEffect,减少不必要的渲染

如果图表数据不需要单独监听其他状态,可以直接在API请求完成后处理图表数据,这样避免额外的useEffect执行:

// 替换原来的两个useEffect为以下代码
useEffect(() => {
    fetch("http://192.168.18.21:8000/performance/solar-overview/")
        .then((response) => {
            if (!response.ok) throw new Error("请求失败");
            return response.json();
        })
        .then((dataValues) => {
            setBlueCardData(dataValues);
            // 直接处理图表数据
            if (dataValues?.pr_hourly) {
                const labels = dataValues.pr_hourly.time;
                const data = dataValues.pr_hourly.pr_hourly;
                setLineData({
                    labels,
                    datasets: [
                        {
                            label: "Values",
                            data,
                            backgroundColor: [
                                "rgba(75,192,192,1)",
                                "#ecf0f1",
                                "#50AF95",
                                "#f3ba2f",
                                "#2a71d0",
                            ],
                            borderColor: "black",
                            borderWidth: 2,
                            fill: true,
                        },
                    ],
                });
            }
            setIsLoading(false);
        })
        .catch((err) => {
            console.error(err);
            setIsLoading(false);
        });
}, []);

关键优化点总结

  • 修正依赖数组:确保依赖项包含需要监听的状态,保证数据更新时触发逻辑
  • 初始状态匹配:blueCardData初始设为null或{},避免访问对象属性时的类型错误
  • 增加错误处理:API请求失败时捕获错误,避免加载状态一直挂起
  • 简化数组处理:直接提取pr_hourly中的time和pr_hourly数组,无需额外map和push操作

内容的提问来源于stack exchange,提问作者Talha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 18:45:37