The useEffect
hook below should set the weather
variable, but it is not doing so -- instead, the React component returns before the hook is called.
Why is the useEffect
hook not called before the React component returns, and how can I fix this problem?
// A React component that shows a given city's weather.
const CityWeather = ({ city }) => {
const [weather, setWeather] = useState({})
useEffect(() => {
axios
.get(`http://api.weatherapi.com/v1/current.json` +
`?key=${process.env.REACT_APP_MY_SUPER_SECRET_WEATHER_API_KEY}` +
`&q=${city}`)
.then(response => {
console.log(`response is ${JSON.stringify(response)}`)
setWeather(response.data)})
},
[city])
console.log(`The value of the weather var is ${JSON.stringify(weather)}`)
return (
<div>
<h1>Weather in {city}</h2>
<p>temperature: {weather.current.temp_c} Celsius</p>
<img src={weather.current.condition.icon} alt="weather forecast"/>
<p>wind speed: {weather.current.wind_mph} mph</p>
<p>wind dir.: {weather.current.wind_dir}</p>
</div>
)
}
This is because the call to the api is asynchronous, which means that the code will continue to execute whilst the fetch happens in the background, when a response is returned it will then callback in the .then()
part of the effect.
A common practice is to show a placeholder whilst loading data:
const CityWeather = ({ city }) => {
const [weather, setWeather] = useState(null);
useEffect(() => {
axios
.get(
`http://api.weatherapi.com/v1/current.json` +
`?key=${process.env.REACT_APP_MY_SUPER_SECRET_WEATHER_API_KEY}` +
`&q=${city}`,
)
.then((response) => {
console.log(`response is ${JSON.stringify(response)}`);
setWeather(response.data);
});
}, [city]);
console.log(`The value of the weather var is ${JSON.stringify(weather)}`);
return (
<div>
{!weather ? (
<h3>Loading the weather!</h3>
) : (
<>
<h2>Weather in {city}</h2>
<p>temperature: {weather.current.temp_c} Celsius</p>
<img src={weather.current.condition.icon} alt="weather forecast" />
<p>wind speed: {weather.current.wind_mph} mph</p>
<p>wind dir.: {weather.current.wind_dir}</p>
</>
)}
</div>
);
};
(Also, I noticed you defaulted weather
to an array ([]
) which is probably causing other issues)