我是React的新手,正在开发一个基于AWS的简单收据扫描Web应用程序(Amplify、AppSync、GraphQL、DynamoDB、S3)。我正在使用useEffect
钩子通过GraphQL调用为当前登录的用户获取数据,并注意到重复运行它。起初,有三次调用,之后我了解并禁用了严格模式。但现在,即使禁用了严格模式,我看到两个电话。
调试显示,如果注解掉setWeekly(getTotalFromItems(response))
,useEffect
只被调用一次,但是即使是setWeekly()
这样小的调用也会导致重复调用。
我仔细阅读了this的帖子以及许多其他帖子,但它们都指出严格模式是罪魁祸首,而这里的情况并非如此。
网络日志附在下面供参考。
有人能帮助我了解可能导致这种双重调用的原因,以及如何解决它吗?
import WebFont from 'webfontloader';
import React, {
useEffect,
useState
} from 'react'
import {
withAuthenticator,
Text,
View
} from '@aws-amplify/ui-react';
import {
MainLayout
} from './ui-components';
import awsExports from "./aws-exports";
Amplify.configure(awsExports);
function App({signOut, user}) {
const [weekly, setWeekly] = useState([]);
useEffect(() => {
WebFont.load({
google: {
families: ['DM Sans', 'Inter']
}
});
async function fetchWeekly(queryTemplate, queryVars) {
try {
const weeklyData = await API.graphql(graphqlOperation(queryTemplate, queryVars))
console.log(weeklyData)
const response = weeklyData.data.getUser.receiptsByPurchaseDateU.items
const total = getTotalFromItems(response) // sums 'total' in [{'date': '...', 'total': 9}, ...]
setWeekly(total)
} catch (err) {
console.log('Error fetching data.');
console.log(err)
}
}
const queryVars = {
username: user.attributes.email,
}
let d = new Date();
d.setDate(d.getDate() - 7);
d = d.toLocaleDateString('en-CA');
let tmpl = generateSummaryTemplate(d) // returns a template string based on d
fetchWeekly(tmpl, queryVars);
console.log('Complete.')
});
return ( <View >
<MainLayout/>
</View >
)
}
export default withAuthenticator(App);
3条答案
按热度按时间goucqfw61#
这里的问题是
useEffect
挂钩缺少依赖项数组。useEffect
回调将触发组件重新呈现的weekly
状态更新入队,并且再次调用useEffect
挂钩。这第二次它再次计算一个值并将weekly
状态更新入队。这是该状态第二次以与当前状态值相同的值入队,并且React决定放弃进一步的重新呈现。请参见放弃状态更新。如果将状态挂接更新为与当前状态相同的值,React将退出,而不渲染子级或激发效果。(React使用www.example.com比较算法。Object.is comparison algorithm.)
解决方案是添加一个具有适当依赖项的依赖项数组。如果您希望效果在组件挂载时在初始渲染后运行一次,请使用空数组。在这种情况下,传递的
user
prop似乎是我目前看到的唯一外部依赖项。将user
添加到依赖项数组。这是为了指示效果应该在何时运行,即在初始挂载/渲染之后以及user
值更改的任何时候。请参见有条件地激发效果。示例:
iyzzxitl2#
首先,在回调函数之后,添加一个依赖数组作为useEffect的第二个参数。此外,我可能建议您在useEffect主体之外有服务函数,不要像那样重载它,这是不合适的。
bihw5rsg3#
这是因为setWeekly()在useEffect()中被调用并触发了另一个渲染。您可以完全删除此useState(),并在fetchWeekly()中返回所需的数据。