javascript 即使禁用了严格模式,React useEffect也被调用了两次

mm9b1k5b  于 2023-01-16  发布在  Java
关注(0)|答案(3)|浏览(193)

我是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);
goucqfw6

goucqfw61#

这里的问题是useEffect挂钩缺少依赖项数组。useEffect回调将触发组件重新呈现的weekly状态更新入队,并且再次调用useEffect挂钩。这第二次它再次计算一个值并将weekly状态更新入队。这是该状态第二次以与当前状态值相同的值入队,并且React决定放弃进一步的重新呈现。请参见放弃状态更新。
如果将状态挂接更新为与当前状态相同的值,React将退出,而不渲染子级或激发效果。(React使用www.example.com比较算法。Object.is comparison algorithm.)
解决方案是添加一个具有适当依赖项的依赖项数组。如果您希望效果在组件挂载时在初始渲染后运行一次,请使用空数组。在这种情况下,传递的user prop似乎是我目前看到的唯一外部依赖项。将user添加到依赖项数组。这是为了指示效果应该在何时运行,即在初始挂载/渲染之后以及user值更改的任何时候。请参见有条件地激发效果。
示例:

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
iyzzxitl

iyzzxitl2#

首先,在回调函数之后,添加一个依赖数组作为useEffect的第二个参数。此外,我可能建议您在useEffect主体之外有服务函数,不要像那样重载它,这是不合适的。

bihw5rsg

bihw5rsg3#

这是因为setWeekly()在useEffect()中被调用并触发了另一个渲染。您可以完全删除此useState(),并在fetchWeekly()中返回所需的数据。

相关问题