英文:
Displaying Error: Too many re-renders in React
问题
这是我编写的代码,用于根据用户输入更改背景视频。背景根据用户输入的地点的天气而变化。
import React, { Fragment, useState, useEffect } from "react";
import cloudy from "../assets/cloudy.mp4";
import sunny from "../assets/sunny.mp4";
import rainy from "../assets/rainy.mp4";
import winter from "../assets/winter.mp4";
const weathers = [cloudy, sunny, rainy, winter];
const Background = (props) => {
const [weather, setWeather] = useState(weathers[1]);
const temp = props.info.current.temp_c;
const rain = props.info.current.precip_mm;
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
return (
<Fragment>
<video autoPlay loop muted className="back-video">
<source src={weather} type="video/mp4" />
</video>
</Fragment>
);
}
这是我在App组件中的返回方式:
return (
<Fragment>
<div className="container">
<h1>Weather App</h1>
<Input newLocation={locationHandler} />
<article>{content}</article>
</div>
<article>{background}</article>
</Fragment>
)
我尝试使用UseEffect来解决重新渲染错误,但在这种情况下,它根本不会改变背景。
useEffect(() => {
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
}, [weather, temp, rain])
或者只将weather
作为依赖项。
这是我的App组件:
import React, { useState, useEffect, useCallback, Fragment } from "react";
import Background from "./components/Background";
import Weather from "./components/Weather";
import Input from "./UI/Input";
function App() {
// ...其他代码
return (
<Fragment>
<div className="container">
<h1>Weather App</h1>
<Input newLoc={locationHandler} />
<article>{content}</article>
</div>
<article>{background}</article>
</Fragment>
);
}
export default App;
英文:
This is the code that I have written to change the background video based on the user input. The background has a video based on the weather of the location the user enters.
import React, { Fragment, useState, useEffect } from "react";
import cloudy from "../assets/cloudy.mp4";
import sunny from "../assets/sunny.mp4";
import rainy from "../assets/rainy.mp4";
import winter from "../assets/winter.mp4";
const weathers = [cloudy, sunny, rainy, winter];
const Background = (props) => {
const [weather, setWeather] = useState(weathers[1]);
const temp = props.info.current.temp_c;
const rain = props.info.current.precip_mm;
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
return (
<Fragment>
<video autoPlay loop muted className="back-video">
<source src={weather} type="video/mp4" />
</video>
</Fragment>
);
}
Here's how I return in the App component :
return (
<Fragment>
<div className="container">
<h1>Weather App</h1>
<Input newLocation={locationHandler} />
<article>{content}</article>
</div>
<article>{background}</article>
</Fragment>
)
I tried using UseEffect since I have a re-rendering error but in that case it doesn't change the background at all
useEffect(() => {
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
}, [weather, temp, rain])
or only weather as a dependency.
Edit: My App component
import React, { useState, useEffect, useCallback, Fragment } from
"react";
import Background from "./components/Background";
import Weather from "./components/Weather";
import Input from "./UI/Input";
function App() {
const [weather, setWeather] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [location, newLocation] = useState("New Delhi");
const locationHandler = (place) => {
newLocation(place);
};
const fetchweatherHandler = useCallback(async () => {
setIsLoading(true);
setError(null);
try {
//console.log(location);
const response = await fetch(
`http://api.weatherapi.com/v1/current.json?
key={apiKey}&q=${location}&aqi=yes`
);
if (!response.ok) {
throw new Error("Something went wrong!");
}
const data = await response.json();
//console.log(data);
setWeather(data);
} catch (error) {
setError(error.message);
}
setIsLoading(false);
}, [location]);
useEffect(() => {
fetchweatherHandler();
}, [fetchweatherHandler]);
let content = <p>Found no weather.</p>;
let background = <p>No Background</p>;
if (weather && Object.keys(weather).length > 0) {
content = weather && <Weather info={weather} />;
background = weather && <Background info={weather} />;
}
if (error) {
content = <p>{error}</p>;
}
if (isLoading) {
content = <p>Loading...</p>;
}
return (
<Fragment>
<div className="container">
<h1>Weather App</h1>
<Input newLoc={locationHandler} />
<article>{content}</article>
</div>
<article>{background}</article>
</Fragment>
);
}
export default App;
答案1
得分: 2
UseEffect
的工作原理如下。无论你在[]
中传递了哪个状态,useEffect
都会监听它的状态,每当状态发生变化时,它都会执行useEffect
内部的代码。它还会在组件挂载时运行一次代码。
在你的情况下,你传递了[weather]
,并且在useEffect
内部改变了setWeather
,从而改变了weather
。因此,useEffect
再次运行,再次设置weather
,导致无限循环和过多的重新渲染错误。
你可以像下面这样使用它,但它不会在每次weather
发生变化时重新渲染。
useEffect(() => {
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
}, [temp, rain])
查看有关"React函数组件中组件生命周期"的主题以了解更多信息。
英文:
So UseEffect
works like this. Which ever state you are passing in the []
, useEffect will listen to its state and whenever the state changes it executes the code inside the useEffect. It also runs the code once the component mounts.
In your case, you are passing [weather]
and inside the useEffect
you are changing the setWeather
which changes weather
. So useEffect
runs again which set's weather
again and it goes on causing an infinite loop and causing too many rerender error.
You can use it like the below but it won't rerender every time weather changes.
useEffect(() => {
if (rain > 2.5) setWeather(weathers[2]);
else if (temp < 8) setWeather(weathers[3]);
}, [temp, rain])
checkout the topic lifecycle of components in react functional components
to know more about this
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论