如何检查 useEffect 中的数据加载
Posted
技术标签:
【中文标题】如何检查 useEffect 中的数据加载【英文标题】:How to check data loading in useEffect 【发布时间】:2021-10-12 00:26:37 【问题描述】:我在我的 React 组件中的 useEffect()
中遇到了一个奇怪的问题。当页面加载时,我必须发出 2 个单独的 axios
请求来获取数据。我正在尝试使用挂钩变量来查看在将数据对象传递给 JSX 之前是否已填充它们。这是我当前的配置:
import React, useState, useEffect from 'react';
import Navbar from '../components/layout/Navbar';
import ContactsCard from '../components/layout/ContactsCard';
import EmailCard from '../components/layout/EmailCard';
import MeetingsCard from '../components/layout/MeetingsCard';
import useParams from "react-router-dom";
import config from './../config/config';
import axios from "axios";
function SummaryPageNew()
let selectName = useParams();
const [contactData, setContactData] = useState();
const [meetingData, setMeetingData] = useState();
const [loadingData, setLoadingData] = useState(true);
//API calls
async function getContactData()
axios
.get(config.apiURL + `/affiliations/name/$selectName`)
.then((response) =>
return setContactData(response.data[0]);
);
async function getMeetingData()
axios
.get(config.apiURL + `/meetings_attendees/name/$selectName`)
.then((response) =>
return setMeetingData(response.data);
);
useEffect((loadingData) =>
getContactData();
getMeetingData();
setLoadingData(false);
if (loadingData)
//if the result is not ready so you make the axios call
getContactData();
getMeetingData();
setLoadingData(false);
, []); // eslint-disable-line react-hooks/exhaustive-deps
return (
<div>
<Navbar />
<div>
<div style= textAlign: "center" >
<h3>Contact Information</h3>
<h5>Profile: selectName</h5>
</div>
loadingData ? (
<p>Loading Please wait...</p>
) : (
<div className="row">
<ContactsCard contactData=contactData />
<EmailCard emailData=meetingData />
<MeetingsCard meetingData=meetingData />
</div>
)
</div>
</div>
)
export default SummaryPageNew
我尝试在 axios
调用中移动 setLoadingData(false)
方法。如果我将它移到getMeetingData()
调用中。这工作......有时。显然,在某些情况下,它会先加载,然后 contactData
不会返回。在当前配置中,DOM 以“Loading Please wait...”呈现。我在这里做错了什么?我该如何解决这个问题?
【问题讨论】:
您不需要专门将loadingData
传递给useEffect((loadingData) =>
,它已经在您的组件顶部,您可以使用它。
【参考方案1】:
你的代码有很多问题。
useEffect
函数不带任何参数。您将 loadingData
声明为参数覆盖了组件中的实际 loadingData 变量,React 不会为此传递值。
您在调用 useEffect 时缺少对 loadingData
的依赖。照原样,只要组件保持挂载,该函数将只执行一次,然后再也不会执行。因此,loadingData 永远不会设置为 false。通常,除非您有充分的理由,否则避免警告有关 useEffect 依赖项是一个坏主意。
我推荐的解决方案是避免为“加载”状态存储额外的状态。相反,我只检查两个状态值是否已被填充,如果没有,则显示“正在加载...”文本。
这给你留下了:
function SummaryPageNew()
let selectName = useParams();
const [contactData, setContactData] = useState();
const [meetingData, setMeetingData] = useState();
const isReady = contactData !== undefined && meetingData !== undefined;
//API calls
async function getContactData() ...
async function getMeetingData() ...
useEffect((loadingData) =>
getContactData();
getMeetingData();
, []);
return (
<div>
<Navbar />
<div>
<div style= textAlign: "center" >
<h3>Contact Information</h3>
<h5>Profile: selectName</h5>
</div>
isReady ? (
<div className="row">
<ContactsCard contactData=contactData />
<EmailCard emailData=meetingData />
<MeetingsCard meetingData=meetingData />
</div>
) : (
<p>Loading Please wait...</p>
)
</div>
</div>
)
react-query 是一个非常强大的库,用于使用钩子异步获取数据。这避免了必须管理很容易不同步的复杂状态。但是,我会先学习 react hooks 的基础知识!
【讨论】:
这些都是很好的答案,但我选择了这个解决方案,因为它是最简单的。谢谢。【参考方案2】:您正在处理异步函数调用。 javascript 在继续执行您的程序之前不会等待您的异步函数完成。这意味着您的调用可能仍在获取,而您已经将 loadingData 设置为 false。您可以通过使用 Promise.all 在异步函数解析时获取回调来解决此问题:
//API calls
async function getContactData()
return axios
.get(config.apiURL + `/affiliations/name/$selectName`)
.then((response) =>
return setContactData(response.data[0]);
);
async function getMeetingData()
return axios
.get(config.apiURL + `/meetings_attendees/name/$selectName`)
.then((response) =>
return setMeetingData(response.data);
);
useEffect(() =>
let mounted = true
return () => mounted = false
Promise.all([getContactData(), getMeetingData()]).then(() =>
if (mounted) setLoadingData(false)
)
, []); // eslint-disable-line react-hooks/exhaustive-deps
还要注意我添加的let mounted = true
:您要确保在异步调用完成时该组件仍然存在。例如,如果通话需要一段时间,那么您可能会离开并不是不可想象的。
最后,禁用react-hooks/exhaustive-deps
并非明智之举。通过一些更改,您可以将代码设置为不再需要忽略。
React 希望你在依赖数组中提供getContactData
、getMeetingData
。您可以通过将数据获取功能移到组件之外来解决此问题。这意味着他们不再有权访问 selectName
变量,但您可以将该变量作为参数提供:
function SummaryPageNew()
let selectName = useParams();
const [contactData, setContactData] = useState();
const [meetingData, setMeetingData] = useState();
const [loadingData, setLoadingData] = useState(true);
//API calls
useEffect(() =>
let mounted = true
Promise.all([
getContactData( selectName ),
getMeetingData( selectName )
]).then(([contactData, meetingData]) =>
if (!mounted) return
setContactData(contactData)
setMeetingData(meetingData)
setLoadingData(false)
)
return () => mounted = false
, [selectName]);
return () // Render your component
async function getContactData( selectName )
return axios
.get(config.apiURL + `/affiliations/name/$selectName`)
.then((response) =>
return setContactData(response.data[0]);
);
async function getMeetingData( selectName )
return axios
.get(config.apiURL + `/meetings_attendees/name/$selectName`)
.then((response) =>
return setMeetingData(response.data);
);
【讨论】:
你可能想看看 react-query,它解决了异步函数获取数据时出现的很多问题。以上是关于如何检查 useEffect 中的数据加载的主要内容,如果未能解决你的问题,请参考以下文章