Meteor.call in for each loop 无限循环运行

Meteor.call in for each loop runs in infinite loop

这里是流星新手,我有一个列表循环,可以对流星方法进行流星调用。我需要将结果填充到另一个对象中,每个列表项作为流星方法响应的键和值。 在所有与项目相关的流星调用完成返回响应后,我想在最后打印完全更新的对象

这是我的以下代码,它在无限循环中运行

  const [codeCoverage, setcodeCoverage] = useState({});
  projectList = ['proj1','proj2','proj3']
  projectList.map((project) => {
    Meteor.call(
      'sonarqb.getProjectStatus',
      { project },
      (error, resp) => {
        if (error) throw new Error(error);
        setCodeCoverage({...codeCoverage, [project] : val.actualValue })
      }
    )
  });

  useEffect(() => {
    console.log(codeCoverage);
  }, [codeCoverage]);

Meteor Method 服务于上述调用

Meteor.methods({
  'sonarqb.getProjectStatus'({ project }) {

    const options = {
      method: 'GET',
      url: `https://sonarqube.com/sonar/api/qualitygates/project_status?projectKey=${project}`,
      headers: {
        Authorization:
          'Basic <auth str>',
      },
    };

    const future = new Future();

    request(options, function(error, response) {
      if (error) throw new Error(error);
      const sonarResponse = JSON.parse(response.body);
      future.return(sonarResponse);
    });
    return future.wait();
  },
});

假设这是一个 React 函数组件,问题是您的 Meteor.call 会在每次组件呈现时发生,包括每次调用 setCodeCoverage 时,即每次调用完成时— 因此是一个无限循环。

您需要将 Meteor.call 包装在 useEffect(或其他东西)中,而不是将它们放在组件的顶层。如果您希望它们只在组件的开头发生一次:

  const [codeCoverage, setcodeCoverage] = useState({});
  const projectList = ['proj1','proj2','proj3'];
  useEffect(() => {
    projectList.forEach((project) => {
      Meteor.call(
        'sonarqb.getProjectStatus',
        { project },
        (error, resp) => {
          if (error) throw new Error(error);
          setCodeCoverage((previous) =>
            {...previous, [project] : val.actualValue });
        }
      )
    })
  }, []); // no deps => run once at beginning

  useEffect(() => {
    console.log(codeCoverage);
  }, [codeCoverage]);