admin管理员组文章数量:1400420
I'm new to React and am working on a simple receipt scanning web app based on AWS (Amplify, AppSync, GraphQL, DynamoDB, S3). I'm using the useEffect
hook to fetch data for the user currently logged in, via a GraphQL call, and am noticing duplicate runs of it. At first, there were three calls, after which I read about and disabled Strict Mode. But now, even with Strict Mode disabled, I am seeing two calls.
Debugging reveals that useEffect
is called only once if I ment out setWeekly(getTotalFromItems(response))
, but even as little as setWeekly()
ends up creating duplicate calls.
I've perused this post as well as numerous others, but they all point to Strict Mode being the primary culprit, which is not the case here.
Network log attached below for reference.
Could someone help me understand what might be causing this double-call, and how to fix it?
import WebFont from 'webfontloader';
import React, {
useEffect,
useState
} from 'react'
import {
withAuthenticator,
Text,
View
} from '@aws-amplify/ui-react';
import {
MainLayout
} from './ui-ponents';
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);
I'm new to React and am working on a simple receipt scanning web app based on AWS (Amplify, AppSync, GraphQL, DynamoDB, S3). I'm using the useEffect
hook to fetch data for the user currently logged in, via a GraphQL call, and am noticing duplicate runs of it. At first, there were three calls, after which I read about and disabled Strict Mode. But now, even with Strict Mode disabled, I am seeing two calls.
Debugging reveals that useEffect
is called only once if I ment out setWeekly(getTotalFromItems(response))
, but even as little as setWeekly()
ends up creating duplicate calls.
I've perused this post as well as numerous others, but they all point to Strict Mode being the primary culprit, which is not the case here.
Network log attached below for reference.
Could someone help me understand what might be causing this double-call, and how to fix it?
import WebFont from 'webfontloader';
import React, {
useEffect,
useState
} from 'react'
import {
withAuthenticator,
Text,
View
} from '@aws-amplify/ui-react';
import {
MainLayout
} from './ui-ponents';
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);
Share
Improve this question
edited Jan 15, 2023 at 1:26
Drew Reese
204k18 gold badges245 silver badges273 bronze badges
asked Jan 15, 2023 at 1:01
sonnysonny
3434 silver badges16 bronze badges
1
-
You might just be missing a dependency array, if your intended result is for the hook to run only once on the initial render. E.g.
useEffect(() => {}, []/*<--- You are missing this? */);
– segFault Commented Jan 15, 2023 at 1:10
3 Answers
Reset to default 4The issue here is that the useEffect
hook is missing a dependency array. The useEffect
callback enqueues a weekly
state update which triggers a ponent rerender and the useEffect
hook is called again. This second time it again putes a value and enqueues a weekly
state update. It's this second time that the state is enqueued with the same value as the current state value and React decides to bail on further rerenders. See Bailing out of State Updates.
If you update a State Hook to the same value as the current state, React will bail out without rendering the children or firing effects. (React uses the Object.is parison algorithm.)
The solution is to add a dependency array with appropriate dependencies. Use an empty array if you want the effect to run once after the initial render when the ponent mounts. In this case it seems the passed user
prop is the only external dependency I see at the moment. Add user
to the dependency array. This is to indicate when the effect should run, i.e. after the initial mount/render and anytime user
value changes. See Conditionally firing an effect.
Example:
useEffect(() => {
...
async function fetchWeekly(queryTemplate, queryVars) {
try {
const weeklyData = await API.graphql(graphqlOperation(queryTemplate, queryVars));
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.');
}, [user]); // <-- user is external dependency
First of add a dependency array as the second argument to the useEffect, after the callback function. Moreover, I may advice that you have service functions outside the useEffect body, don't overload it like that, is not appropirate.
It’s because setWeekly() is called within your useEffect() and triggers another render. You may remove this useState() entirely and instead return the data you need in fetchWeekly().
本文标签: javascriptReact useEffect called twice even with strict mode disabledStack Overflow
版权声明:本文标题:javascript - React useEffect called twice even with strict mode disabled - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744254845a2597427.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论