Not sure why but a function inside my ternary is causing an infinite loop. The setUnit function, which is setting a state in redux, causes the page to loop infinitely/ breaks the page and I cannot put my figure on why. The function modifies the ternary that the component is dependent on, so maybe that's why?
Current.js
const Current = () => {
const locationData = useSelector((state) => state.locationData);
const locationName = useSelector((state) => state.locationName.name);
const weatherData = useSelector((state) => state.weather.data);
const unit = useSelector((state) => state.units.unit);
const dispatch = useDispatch();
function setUnit(unit) {
if (unit === "metric") {
console.log("metric!");
dispatch(unitActions.setToMetric());
} else {
console.log("imperial!");
dispatch(unitActions.setToImperial());
}
}
return (
<div className="main-container">
<h2 className="location">{locationName}</h2>
<div className="top">
<img
src={`https://openweathermap.org/img/wn/${weatherData.current.weather[0].icon}@2x.png`}
alt="Weather icon"
className="weather-icon"
/>
<h1 className="temp">{Math.floor(weatherData.current.temp)}°</h1>
<div className="units-container">
{unit === "metric" ? (
<div>
<div className="unit" id="C">
<h2>C</h2>
</div>
<div
className="unit"
id="F"
onClick={setUnit("imperial")}
>
<h2>F</h2>
</div>
<div className="background"></div>
</div>
) : (
<div>
<div className="unit" id="F">
<h2>F</h2>
</div>
<div
className="unit"
id="C"
onClick={setUnit("metric")}
>
<h2>C</h2>
</div>
<div className="background"></div>
</div>
)}
</div>
</div>
<div className="bottom">
<h2 className="description">
{weatherData.current.weather[0].description[0].toUpperCase()}
{weatherData.current.weather[0].description.substring(1)}
</h2>
<h4 className="timestamp">
Updated as of {convertTime(weatherData.current.dt, "HH-MM")}
</h4>
<div className="bottom-icons">
<div className="icons" id="top-icons">
<div className="icon-element">
Feels like {weatherData.current.feels_like}°
</div>
<div className="icon-element" id="wind">
Wind {weatherData.current.wind_speed}km
</div>
<div className="icon-element" id="visibility">
Visibility {Math.round(weatherData.current.visibility / 1000)} km
</div>
</div>
<div className="icons">
<div className="icon-element">
Barometer {weatherData.current.pressure} mb
</div>
<div className="icon-element" id="humidity">
Humidity {weatherData.current.humidity}%;
</div>
<div className="icon-element" id="dew">
Dew Point {Math.round(weatherData.current.dew_point)}°
</div>
</div>
</div>
</div>
</div>
);
};
CodePudding user response:
Currently setUnit
is being called immediately, changing state and causing it to continuously re-render. Instead, pass in your setUnit
function to onClick
to call it only when the onClick
event is fired: onClick={() => setUnit("imperial")}
.
CodePudding user response:
Another option is to change setUnit
to return an event handler. An advantage of this approach is the event
is colocated with the effect -
const setUnit = (unit) => (event) => {
// access to `event` here