![](/img/trans.png)
[英]this.setState making infinite loop outside of array.map function
[英]setState causes infinite loop even though it is outside render function
我目前正在使用 openweatherapp API 開發一個簡單的天氣應用程序。 該應用程序旨在從兩個端點獲取數據:一個返回您所在城市的當前天氣,另一個返回未來 5 天的天氣預報。 該應用程序還應在 60 秒后觸發重新獲取數據的事件。 這就是我嘗試構建我的解決方案的方式:
在 App.js 中,我正在獲取數據,然后將其作為道具傳遞給其他兩個組件,一個處理當前天氣,另一個處理天氣預報。 在 CurrentWeatherForecast 組件中,我還啟動了使用鈎子每秒更新狀態的函數。 當計時器達到 60 秒時,我正在調用我作為 App.js 中的道具傳遞的“handleRefresh”函數。 (在 App.js 中是實際更新發生的地方)。 “handleRefresh”函數在 App.js 的 render 方法之外,它更新一個“step”變量,然后應該導致組件重新渲染並重新獲取數據。 問題是,在調用 setState 時,該函數會導致無限循環,我不明白為什么,因為該函數在 render 方法之外。 我將在下面發布我的代碼。
import React, { Component } from "react";
import { CurrentWeatherForecast } from "./components/CurrentWeatherForecast";
import { NextDaysWeatherForecast } from "./components/NextDaysWeatherForecast";
export class App extends Component {
constructor(props) {
super(props);
this.state = {
currentWeather: [],
nextDaysWeather: [],
step: 0,
};
}
componentDidMount() {
const { step } = this.state;
var currentWeather;
var nextDaysWeather; // step is used to indicate wether I want to fetch data or not
if (step === 0) {
fetch(
"https://api.openweathermap.org/data/2.5/weather?q=London&appid=1fc71092a81b329e8ce0e1ae88ef0fb7"
)
.then((response) => {
const contentType = response.headers.get("content-type");
if (
!contentType ||
!contentType.includes("application/json")
) {
throw new TypeError("No JSON data!");
}
return response.json();
})
.then((data) => {
currentWeather = data;
})
.catch((error) => console.error(error));
fetch(
"https://api.openweathermap.org/data/2.5/forecast?q=London&appid=1fc71092a81b329e8ce0e1ae88ef0fb7"
)
.then((response) => {
const contentType = response.headers.get("content-type");
if (
!contentType ||
!contentType.includes("application/json")
) {
throw new TypeError("No JSON data!");
}
return response.json();
})
.then((data) => {
let requiredData = data.list.slice(0, 5);
nextDaysWeather = requiredData;
})
.catch((error) => console.error(error));
let f = setTimeout(() => {
this.setState({
currentWeather: currentWeather,
nextDaysWeather: nextDaysWeather,
step: 1, // updating step to 1 after fetching the data
});
}, 1000);
}
}
handleRefresh = () => {
const { step } = this.state;
console.log(step);
this.setState({ step: 0 }); // updating the step to 0 this causes the infinite loop
};
render() {
const { currentWeather, nextDaysWeather } = this.state;
return (
<div>
<CurrentWeatherForecast
currentWeather={currentWeather}
handleRefresh={this.handleRefresh}
/>
<NextDaysWeatherForecast nextDaysWeather={nextDaysWeather} />
</div>
);
}
}
export default App;
這是在 App.js 中忽略 NextDaysWeatherForecast 組件,因為它現在是空的
import React, { useEffect, useState } from "react";
export const CurrentWeatherForecast = (props) => {
const { currentWeather } = props;
const [progressValue, setValue] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setValue((progressValue) =>
progressValue < 61 ? progressValue + 1 : (progressValue = 0)
);
}, 1000);
return () => clearInterval(interval);
}, []);
if (progressValue === 60) {
props.handleRefresh(); // calling the handleRefresh function passed from App.js
}
return (
<div>
<label htmlFor="file">Downloading progress:</label>
<progress id="file" value={progressValue} max="60">
{progressValue}%
</progress>
</div>
);
};
這是 NextWeatherForecast 組件,我在其中啟動計時器,然后調用我作為道具傳遞的“handleRefresh”函數。
提前謝謝你們!
看看這個 effect-phase 和 render-phase 代碼,並嘗試猜測哪里出了問題。
useEffect(() => {
const interval = setInterval(() => {
setValue((progressValue) =>
progressValue < 61 ? progressValue + 1 : (progressValue = 0)
);
}, 1000);
return () => clearInterval(interval);
}, []);
if (progressValue === 60) {
props.handleRefresh(); // calling the handleRefresh function passed from App.js
}
特別是這個聞起來像溢出:在渲染階段調用的導致重新渲染的函數(我們知道handleRefresh
會導致重新渲染。
if (progressValue === 60) {
props.handleRefresh(); // calling the handleRefresh function passed from App.js
}
現在,讓我們尋找一些應該停止溢出的東西(也就是說,它嘗試將progressValue
設置為 60 以外的其他值,一旦它是 60)。
這里是:
progressValue < 61 ? progressValue + 1 : (progressValue = 0)
除了,這僅每 1000 毫秒觸發一次。 這意味着您的組件在一整秒內陷入了重新渲染循環。 一旦設置為60
,React 開始瘋狂渲染,並在很短的時間內超過渲染限制,而progressValue
距離設置為 0 仍有很多很多毫秒。
一個示例解決方案是在另一個效果中檢查progressValue === 60
。
export const CurrentWeatherForecast = (props) => {
const { currentWeather } = props;
const [progressValue, setValue] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setValue(prevProgressValue => prevProgressValue === 60 ? 0 : prevProgressValue + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
useEffect(() => progressValue === 60 && props.handleRefresh(), [progressValue]);
return (
<div>
<label htmlFor="file">Downloading progress:</label>
<progress id="file" value={progressValue} max="60">
{progressValue}%
</progress>
</div>
);
};
嘗試這個:
import React, { useEffect, useState } from "react";
export const CurrentWeatherForecast = ({ currentWeather }) => {
useEffect(() => {
const interval = setInterval(() => {
props.handleRefresh();
}, 60000);
return () => clearInterval(interval);
}, []);
return (
<div>
your codes goes here...
</div>
);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.