[英]Need help figuring out how to update state from the values of a list gotten by an async function in firestore
I currently have code that when entering a screen with useFocusEffect, fetches an array of payments, and for each payment within that list there is another async function which is called that retrieves data about that payment including the value of it.我目前有代码,当使用 useFocusEffect 进入屏幕时,获取一组付款,并且对于该列表中的每笔付款,还有另一个异步 function 调用它来检索有关该付款的数据,包括它的价值。 I am trying to sum up the values of the payments in this list and set a state variable too it, but according to my understanding they are all happening at the same time and the state value is updated to just the value of the last payment that is read from the array.
我试图总结此列表中的付款值并设置一个 state 变量,但根据我的理解,它们都是同时发生的,并且 state 值更新为最后一次付款的值从数组中读取。 What would be the best way to make it so that my state updates to the sum of the values of the payments?
使我的 state 更新为付款总和的最佳方法是什么? I've tried various combinations of solutions with storing values in local variables and setting the state to the local variable in the end but nothing seems to work.
我尝试了各种解决方案组合,将值存储在局部变量中,最后将 state 设置为局部变量,但似乎没有任何效果。 Below is the code to help visualize what I am doing.
下面是帮助可视化我在做什么的代码。
fetchPaymentsInChat(props.threadID).then((payments) => {
payments.forEach(pid => {
fetchPayment(pid).then(payment => {
setAmountReceive(payment.value + amountReceive);
console.log(amountReceive, payment.value);
if (payment.sender == username) {
setAmountReceive(amountReceive + payment.value);
}
})
});
});
Any advice would be appreciated!任何意见,将不胜感激!
Ultimately, it comes down to improper Promise chaining and a misunderstanding of how setState
callbacks work.最终,它归结为不正确的 Promise 链接和对
setState
回调如何工作的误解。
fetchPaymentsInChat(props.threadID)
.then((payments) => {
payments.forEach(pid => {
fetchPayment(pid) // <- floating Promises in loop
.then(payment => {
setAmountReceive(payment.value + amountReceive); // <- sums early?
console.log(amountReceive, payment.value); // improperly attempts to use new amountReceive value
if (payment.sender == username) {
setAmountReceive(amountReceive + payment.value); // <- attempts to sum again?
}
})
});
});
When using a setState
callback from a useState
call, it will set the value for the next render of your component - it doesn't update the value for the current render.当使用来自
useState
调用的setState
回调时,它将为组件的下一次渲染设置值——它不会更新当前渲染的值。 There are resources online that explain how useState
works, but for the purpose of showing how it's not updated immediately, we can look at this pseudo-code:网上有资源解释
useState
是如何工作的,但为了展示它是如何不立即更新的,我们可以看一下这段伪代码:
const useState = (initValue) => {
useState._value = "_value" in useState ? useState._value : initValue;
return [useState._value, (v) => useState._value = v]
}
let [value, setValue] = useState(0);
console.log(value); // => 0
setValue(1);
console.log(value); // => 0 [but _value is now 1]
setValue(value + 1);
console.log(value); // => 0 [but _value is still 1 (0 + 1)]
// --- start next loop --- (imagine we've gone back to useState(0) line)
[value, setValue] = useState(0);
console.log(value); // => 1
setValue(1);
console.log(value); // => 1 [but _value is still 1]
setValue(value + 1);
console.log(value); // => 1 [but _value is now 2 (1 + 1)]
// --- start next loop --- (imagine we've gone back to useState(0) line again)
[value, setValue] = useState(0);
console.log(value); // => 2
setValue(1);
console.log(value); // => 2 [but _value is now back to 1]
setValue(value + 1);
console.log(value); // => 2 [but _value is now 3 (2 + 1)]
// ...
As can be seen from the above lines, summing against the current value doesn't work as expected.从上面几行可以看出,对当前值求和没有按预期工作。 While a
setState
callback can be fed a function another callback to update the value that looks like (oldValue) => newValue
, we don't need to use it here.虽然可以向
setState
回调提供 function 另一个回调来更新看起来像(oldValue) => newValue
的值,但我们不需要在这里使用它。
This is because both issues can be solved by fixing up the Promise chains using Promise.all
combined with Array#map
and Array#reduce
.这是因为这两个问题都可以通过使用
Promise.all
结合Array#map
和Array#reduce
修复 Promise 链来解决。
fetchPaymentsInChat(props.threadID)
.then((paymentIDs) => {
return Promise.all(
paymentIDs.map(pid => {
return fetchPayment(pid)
.then(paymentDetails => paymentDetails.value)
})
);
})
.then((paymentValues) => {
const paymentSum = paymentValues.reduce((acc, val) => acc + val, 0);
setAmountReceive(paymentSum);
})
.catch(err => {
/* don't forget error handling */
})
If the intention is to only sum the payments where the sender is username
, instead use:如果打算仅对发件人为
username
的付款求和,请改用:
fetchPaymentsInChat(props.threadID)
.then((paymentIDs) => {
return Promise.all(
paymentIDs.map(pid => {
return fetchPayment(pid)
.then(paymentDetails => {
return paymentDetails.sender === username ? paymentDetails.value : 0
})
})
);
})
.then((paymentValues) => {
const paymentSum = paymentValues.reduce((acc, val) => acc + val, 0);
setAmountReceive(paymentSum);
})
.catch(err => {
/* don't forget error handling */
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.