在 UseEffect 中为两个 API 调用设置 Promise
Posted
技术标签:
【中文标题】在 UseEffect 中为两个 API 调用设置 Promise【英文标题】:Setting up Promise for two API calls in UseEffect 【发布时间】:2021-03-31 20:57:01 【问题描述】:const [activities, setActivities] = useState([""]);
const [contact, setContact] = useState();
const currentActivity = activities[0]
let contactId = currentActivity.contacts
useEffect(() =>
API.getActivities()
.then(res =>
setActivities(res.data)
).catch((err) => console.log(err))
API.getContact(contactId)
.then(res =>
setActivities(res.data)
).catch((err) => console.log(err))
, []);
console.log(currentActivity)
console.log(contactId)
console.log(contact)
第一个调用设置包含联系人 ID 的活动状态。我需要 id 来运行第二次呼叫以获取联系信息。我相信我需要设定一个承诺,但我被卡住了。当我运行代码时,联系人 ID 没有及时返回以拉取联系人。另一种解决方案可能是调用所有联系人并循环以匹配联系人返回的 id。当我尝试过时,“联系人”状态也返回未定义。
【问题讨论】:
查看 init async await,或者您可以将第二个 promise 嵌套在第一个 promise 的.then
中
【参考方案1】:
如果这有帮助,请告诉我。我还没有测试过,可能需要做一些小改动。
useEffect(async() =>
const resActivities=await API.getActivities()
setActivities(resActivities.data)
const promises=resActivities.data.map(item=>API.getContact(item.contactId)) // assuming contactId property exists
const resp=await Promises.all(promises)
setContact(resp.flat())
, []);
【讨论】:
【参考方案2】:我在 Wirespec 上创建了几个 API 来生成可以测试的响应。您可以使用 Wirespec 免费创建自己的 API。
getRandomUser AP我: https://wirespec.dev/Wirespec/projects/apis/***/apis/getRandomUserId
getRandomUser 响应: https://api.wirespec.dev/wirespec/***/getrandomuserid
getUserDetails API: https://wirespec.dev/Wirespec/projects/apis/***/apis/getUserDetails
getUserDetails 响应: https://api.wirespec.dev/wirespec/***/getuserdetails?id=3
这里是测试代码。提供了两种解决方案:
let userDetails;
new Promise(function (resolve)
let user = JSON.parse(httpGet("https://api.wirespec.dev/wirespec/***/getrandomuserid"));
resolve(user);
).then(function (user)
userDetails = JSON.parse(httpGet("https://api.wirespec.dev/wirespec/***/getuserdetails?id=" + user.id));
console.log("firstName: " + userDetails.firstName + ", lastName: " + userDetails.lastName);
);
// A shorter way and cleaner approach...
getUserDetails()
.then (function (userDetails)
console.log("firstName: " + userDetails.firstName + ", lastName: " + userDetails.lastName);
);
async function getUserDetails()
let user = await JSON.parse(httpGet("https://api.wirespec.dev/wirespec/***/getrandomuserid"));
let userDetails = await JSON.parse(httpGet("https://api.wirespec.dev/wirespec/***/getuserdetails?id=" + user.id));
return userDetails;
function httpGet(url)
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", url, false);
xmlHttp.send(null);
return xmlHttp.responseText;
【讨论】:
【参考方案3】:您“同时”运行两个 api 调用,因此我们可以假设您永远不会在进行联系人调用时定义 contactId。
所以基本上你想在你有一个contactId后运行联系人呼叫,而不是之前。为此,您可以添加一个额外的效果,该效果将在 contactId 值更改时运行。
另请注意,在您的 sn-p 中,您在联系人呼叫后使用 setActivities
而不是 setContact
。
这将解决上述问题
const [activities, setActivities] = useState([""]);
const [contact, setContact] = useState();
const currentActivity = activities[0]
let contactId = currentActivity.contacts
useEffect(() =>
API.getActivities()
.then(res =>
setActivities(res.data)
).catch((err) => console.log(err))
, []);
useEffect(() =>
// Do nothing when contactId is not defined
if(!contactId) return;
API.getContact(contactId)
.then(res =>
setContact(res.data) // I also modified this line. It was updating the activities in your snippet
).catch((err) => console.log(err))
, [contactId]); // This effect will be run every time the contactId changes
console.log(currentActivity)
console.log(contactId)
console.log(contact)
【讨论】:
以上是关于在 UseEffect 中为两个 API 调用设置 Promise的主要内容,如果未能解决你的问题,请参考以下文章
React - 是不是在 useEffect 中调用 API
在 useEffect API 调用之前调用 useState 变量
在 useEffect 中处理 forEach 后调用 setstate
如何阻止多个重新渲染执行多个 api 调用 useEffect?