Javascript setState会导致无限循环,即使它在渲染函数之外
我目前正在使用OpenWeatherAppAPI开发一个简单的天气应用程序。开发该应用程序是为了从两个端点获取数据:一个端点返回您所在城市的当前天气,另一个端点返回未来5天的天气预报。应用程序还应该在60秒后触发一个事件,重新获取数据。这就是我试图构建解决方案的方式: 在App.js中,我获取数据,然后将其作为道具传递给另外两个组件,一个处理当前天气,另一个处理天气预报。在CurrentWeatherForecast组件中,我还启动了使用挂钩每秒更新状态的功能。当计时器达到60秒时,我正在调用“handleRefresh”函数,该函数是我从App.js作为道具传递下来的。(实际更新发生在App.js中)。“handleRefresh”函数不在App.js的render方法中,它会更新一个“step”变量,该变量会导致组件重新渲染并重新获取数据。问题是调用setState函数会导致无限循环,我不明白为什么,因为该函数在render方法之外。我将在下面发布我的代码Javascript setState会导致无限循环,即使它在渲染函数之外,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,我目前正在使用OpenWeatherAppAPI开发一个简单的天气应用程序。开发该应用程序是为了从两个端点获取数据:一个端点返回您所在城市的当前天气,另一个端点返回未来5天的天气预报。应用程序还应该在60秒后触发一个事件,重新获取数据。这就是我试图构建解决方案的方式: 在App.js中,我获取数据,然后将其作为道具传递给另外两个组件,一个处理当前天气,另一个处理天气预报。在CurrentWeatherForecast组件中,我还启动了使用挂钩每秒更新状态的功能。当计时器达到60秒时,我正在调用“
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;
import React,{Component}来自“React”;
从“/components/CurrentWeatherForecast”导入{CurrentWeatherForecast}”;
从“/components/nextdaysheatherforecast”导入{nextdaysheatherforecast}”;
导出类应用程序扩展组件{
建造师(道具){
超级(道具);
此.state={
当前天气:[],
下一天:【】,
步骤:0,
};
}
componentDidMount(){
const{step}=this.state;
天气变化;
var nextdayseagher;//步骤用于指示是否要获取数据
如果(步骤==0){
取回(
"https://api.openweathermap.org/data/2.5/weather?q=London&appid=1fc71092a81b329e8ce0e1ae88ef0fb7"
)
。然后((响应)=>{
const contentType=response.headers.get(“内容类型”);
如果(
!contentType||
!contentType.includes(“应用程序/json”)
) {
抛出新的TypeError(“没有JSON数据!”);
}
返回response.json();
})
。然后((数据)=>{
当前天气=数据;
})
.catch((错误)=>console.error(错误));
取回(
"https://api.openweathermap.org/data/2.5/forecast?q=London&appid=1fc71092a81b329e8ce0e1ae88ef0fb7"
)
。然后((响应)=>{
const contentType=response.headers.get(“内容类型”);
如果(
!contentType||
!contentType.includes(“应用程序/json”)
) {
抛出新的TypeError(“没有JSON数据!”);
}
返回response.json();
})
。然后((数据)=>{
让requiredData=data.list.slice(0,5);
nextDaysWeather=所需数据;
})
.catch((错误)=>console.error(错误));
设f=setTimeout(()=>{
这是我的国家({
currentWeather:currentWeather,
下一天出汗:下一天出汗,
步骤:1,//获取数据后将步骤更新为1
});
}, 1000);
}
}
handleRefresh=()=>{
const{step}=this.state;
控制台日志(步骤);
this.setState({step:0});//将步骤更新为0会导致无限循环
};
render(){
const{currentWeather,nextDaysWeather}=this.state;
返回(
);
}
}
导出默认应用程序;
这是在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>
);
};
import React,{useffect,useState}来自“React”;
导出常数CurrentWeatherForecast=(道具)=>{
const{currentWeather}=道具;
const[progressValue,setValue]=useState(0);
useffect(()=>{
常量间隔=设置间隔(()=>{
设置值((进程值)=>
progressValue<61?progressValue+1:(progressValue=0)
);
}, 1000);
return()=>clearInterval(interval);
}, []);
如果(progressValue==60){
props.handleRefresh();//调用从App.js传递的handleRefresh函数
}
返回(
下载进度:
{progressValue}%
);
};
这是第二个预演组件,我在其中启动计时器,然后调用“handleRefresh”函数,我把它作为道具传递下来
提前谢谢各位 查看此效果阶段和渲染阶段代码,并尝试猜出错误
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
}
现在,让我们寻找一种可以阻止溢出的方法(即,它尝试将
progressValue
设置为60以外的值,一旦设置为60)
这是:
progressValue < 61 ? progressValue + 1 : (progressValue = 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
}
现在,让我们寻找一种可以阻止溢出的方法(即,它尝试将
progressValue
设置为60以外的值,一旦设置为60)
这是:
progressValue < 61 ? progressValue + 1 : (progressValue = 0)
试试这个:
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>
);
};
import React,{useffect,useState}来自“React”;
导出常数CurrentWeatherForecast=({currentWeather})=>{
useffect(()=>{
常量间隔=设置间隔(()=>{
props.handleRefresh();
}, 60000);
return()=>clearInterval(interval);
}, []);
返回(
你的密码在这里。。。
);
};
试试这个:
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>
);
};
import React,{useffect,useState}来自“React”;
导出常数CurrentWeatherForecast=({currentWeather})=>{
useffect(()=>{
常量间隔=设置间隔(()=>{
props.handleRefresh();
}, 60000);
return()=>clearInt