首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >即使setState是外部呈现函数,它也会导致无限循环。

即使setState是外部呈现函数,它也会导致无限循环。
EN

Stack Overflow用户
提问于 2020-09-17 09:47:47
回答 2查看 374关注 0票数 1

我目前正在开发一个简单的天气应用程序,使用openwea热处理API。该应用程序用于从两个端点获取数据:一个返回城市当前的天气,另一个返回未来5天的天气预报。应用程序还应该在60秒后触发一个重新获取数据的事件。这就是我试图构建我的解决方案的方式:

在App.js中,我获取数据,然后将其作为道具传递给另外两个组件,一个组件处理当前天气,另一个组件用于天气预报。在CurrentWeatherForecast组件中,我还启动了使用钩子每秒更新状态的函数。当计时器达到60秒时,我将调用"handleRefresh“函数,该函数是作为App.js的道具传递下来的。(在App.js中,实际更新是在哪里进行的)。"handleRefresh“函数位于App.js的呈现方法之外,它更新了一个"step”变量,该变量将导致组件重新呈现并重新获取数据。问题是,在调用setState时,函数会导致无限循环,但我不明白为什么,因为函数在render方法之外。我会在下面贴出我的代码。

代码语言:javascript
复制
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组件的,因为它现在是空的。

代码语言:javascript
复制
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“函数。

谢谢,伙计们!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-17 10:45:33

看看这个效果阶段和渲染阶段代码,并尝试猜测什么是错误的。

代码语言:javascript
复制
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会导致重发器)。

代码语言:javascript
复制
if (progressValue === 60) {
    props.handleRefresh(); // calling the handleRefresh function passed from App.js
}

现在,让我们来看看应该阻止溢出的东西(也就是说,它尝试将progressValue设置为60以外的东西,一旦它设置为60)。

下面是:

代码语言:javascript
复制
progressValue < 61 ? progressValue + 1 : (progressValue = 0)

除了,这只会每1000毫秒点燃一次。这意味着您的组件在重发循环中停留了整整一秒钟。一旦将其设置为60,React就会像疯了一样开始呈现,并且在很短的时间内就会超过呈现限制,而progressValue离被设置为0还有很多毫秒的距离。

一个示例解决方案是检查另一个效果中的progressValue === 60

代码语言:javascript
复制
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>
    );
};
票数 2
EN

Stack Overflow用户

发布于 2020-09-17 11:05:18

试试这个:

代码语言:javascript
复制
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>
);
};
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/63935451

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档