reactjs 仅在useEffect内运行一次函数

bihw5rsg  于 2022-12-18  发布在  React
关注(0)|答案(2)|浏览(319)

我有一个useEffect钩子,它有一个函数callForcast(),它依赖于callWeather,所以当callWeather()函数运行时,callForcast()运行。callweather()是通过onClick和callForcast()调用的,我在useEffect()中添加了一个调用,但这会导致无限循环。
我怎样才能让这个函数运行一次。

useEffect (() => {
    async function callForcast() {
      const key = "";
      // Get lat & lon from the previous data fetch
      const lon = weatherData.coord.lon
      const lat = weatherData.coord.lat
      // Get forcast data
      const forcastWeatherUrl = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&units=metric&appid=${key}`
      const forcastWeatherResponse = await fetch(forcastWeatherUrl);
      if (!forcastWeatherResponse.ok) {
        const message = `An error has occured: ${forcastWeatherResponse.status}`;
        throw new Error(message);
      } 
      const forcastDataResponse = await forcastWeatherResponse.json();
      // Update state with the forcast data
      setForcastData(forcastDataResponse);
    }
    // Causing infinite loop
    callForcast(); 

  }, [callWeather])

这是callForcast函数所依赖的

async function callWeather() {
    const key = "";
    // Get location by user
    let location = formData.location;
    // Url for current weather
    const currentWeatherUrl = `https://api.openweathermap.org/data/2.5/weather?q=${location}&units=metric&appid=${key}`;
    // Get the current weather
    const currentWeatherResponse = await fetch(currentWeatherUrl);
    if (!currentWeatherResponse.ok) {
      // Return this message if an error
      const message = `An error has occured: ${currentWeatherResponse.status}`;
      throw new Error(message);
    }
    // Get data if no error
    const weatherDataResponse = await currentWeatherResponse.json();
    // Update state with data
    setWeatherData(weatherDataResponse);
  }
mw3dktmi

mw3dktmi1#

为什么它依赖于callWeather?它不使用callWeather
它一遍又一遍地执行,大概是因为无论callWeather是什么,它在每次渲染时都会改变(可能在每次渲染时都被重新声明和/或重新赋值)。
如果此效果只应执行一次,请使用空依赖项数组:

useEffect(() => {
  // the code in the effect
}, []);

这将仅在组件首次加载时执行一次效果。
或者...
当运行callWeather()函数时,callForcast()将运行
如果你想在每次调用callWeather()时都调用callForcast(),那么useEffect就是一个错误的工具。只需定义你想调用的函数,然后在你想调用它的时候调用它。例如:

const callForcast = () => {
  // the code in the function
};

const callWeather = () => {
  // the code in the function
  
  callForcast();
};

另一种可能性...
如果您有一个状态值 * 是 * 依赖关系,并且希望在依赖关系更改时随时调用效果,请将该状态值用作依赖关系:

useEffect(() => {
  // the code in the effect
}, [weatherData]);


或者...
如果此函数只需要其他操作提供的一些数据,请提供该数据。例如:

const callForcast = (dataNeeded) => {
  // the code in the function
};

const callWeather = () => {
  // the code in the function
  
  callForcast(someData);
};

总的来说,您并不完全清楚在什么情况下需要执行callForcast。(尽管在我键入此内容时,您可能会在问题中澄清这一点。)但是,* 在您的原始代码中 *,它在每个渲染上执行的原因是因为callWeather在每个渲染上都在更改,并且 * 肯定 * 是错误的依赖项。

1rhkuytd

1rhkuytd2#

尝试在效果中调用callWeather。如果是异步的,可以在callForcast中调用

useEffect (() => {
    // callWeather();

    async function callForcast() {
      await callWeather();

      const key = "";
      // Get lat & lon from the previous data fetch
      const lon = weatherData.coord.lon
      const lat = weatherData.coord.lat
      // Get forcast data
      const forcastWeatherUrl = `https://api.openweathermap.org/data/2.5/forecast?lat=${lat}&lon=${lon}&units=metric&appid=${key}`
      const forcastWeatherResponse = await fetch(forcastWeatherUrl);
      if (!forcastWeatherResponse.ok) {
        const message = `An error has occured: ${forcastWeatherResponse.status}`;
        throw new Error(message);
      } 
      const forcastDataResponse = await forcastWeatherResponse.json();
      // Update state with the forcast data
      setForcastData(forcastDataResponse);
    }
    // Causing infinite loop
    callForcast(); 

  }, [callWeather])

此外,你应该只是有callWeather返回你的数据在一个承诺,所以你可以提取它在你的callForcast fn.像const data = await callWeather();
编辑:查看您可能需要的更新

// will run callForcast every time 
  useEffect (() => {
    async function callForcast() {
       ...
    }
    callForcast(); 
  }, [weatherData]);

async function callWeather() {
    ...
    setWeatherData(weatherDataResponse);
    return weatherDataResponse;
  }

  useEffect (() => {
    async function callForcast() {
       const weatherData = await callWeather();
       ...
    }
    callForcast(); 
  }, [callWeather]);

相关问题