Reputation: 51
In this component I'm trying to toggle between Celsius to Fahrenheit. I have two functions that do that and save in to the state. When I click at onToggleToFahrenheit
the function executes and does the job properly, but when I click at onToggleToCelsius
, the component rendered and the state reset.
import React, { useState, useEffect } from "react";
export const CurrentWeather = ({ data }) => {
console.log("renderrrr component");
const [currWeatherFormat, setcurrWeatherFormat] = useState({
currTemp: data.main.temp,
});
useEffect(() => {
console.log("aaa", currWeatherFormat);
}, [currWeatherFormat]);
const onToggleToFahrenheit = (celsius) => {
console.log("celsius", celsius);
const fahrenheit = celsius * 1.8 + 32;
setcurrWeatherFormat({ ...currWeatherFormat, currTemp: fahrenheit });
};
const onToggleToCelsius = (fahrenheit) => {
console.log("fehrenheit", fahrenheit);
const celsius = ((fahrenheit - 32) * 5) / 9;
setcurrWeatherFormat({ ...currWeatherFormat, currTemp: celsius });
};
return (
<div className="bottom-left">
<h1 id="temperature">{data.main.temp}</h1>
<h2
onClick={() => onToggleToCelsius(data.main.temp)}
id="celsius"
>
°C
</h2>
<h2 id="temp-divider">/</h2>
<h2
onClick={() => onToggleToFahrenheit(data.main.temp)}
id="fahrenheit"
>
°F
</h2>
</div>
);
};
Upvotes: 2
Views: 1432
Reputation: 202605
Both the onToggleToFahrenheit
and onToggleToCelsius
functions enqueue a state update and will trigger a rerender. State isn't resetting, it is being updated.
I don't see any overt issues with the code other than that it isn't rendering the local state, i.e. <h1 id="temperature">{data.main.temp}</h1>
instead of <h1 id="temperature">{currWeatherFormat.currTemp}</h1>
, and also that it is considered anti-pattern to store derived state like a computed conversion from Fahrenheit to Celsius, and back, based on a toggle. In other words, the state should be what unit you want to display the temp in and do the conversion on the fly when rendering.
Instead of converting and storing the temp locally, use a state to indicate what unit to render the temp as.
Example:
const CurrentWeather = ({ data }) => {
const [inCelsius, setInCelsius] = useState(false);
const toggleTempUnit = () => setInCelsius((c) => !c);
const getTemp = (temp) =>
Number(inCelsius ? ((temp - 32) * 5) / 9 : temp).toFixed(2);
return (
<div className="bottom-left">
<h1 id="temperature">
{getTemp(data.main.temp)}°{inCelsius ? "C" : "F"}
</h1>
<button type="button" onClick={toggleTempUnit}>
°F|°C
</button>
</div>
);
};
...
<CurrentWeather data={{ main: { temp: 32.21 } }} />
Upvotes: 2
Reputation: 485
Changes to state will cause your component to re-render - you are doing this in both of your onToggle methods by calling setcurrWeatherFormat with a new value.
I think the issue here is that you are always displaying the temperature using the components prop value and not the state value that you modify. Try changing
<h1 id="temperature">{data.main.temp}</h1>
To
<h1 id="temperature">{currWeatherFormat.currTemp}</h1>
Additionally, what is the data.main.temp being passed to the component? Is this a celsius or fahrenheit value or something else? You may not need to do one of the conversions ...
Upvotes: 0