Hook not updating when being called in useEffect

Viewed 69

I'm having problem with updating state after retrieving data from my API. The API response is just fine but for some reason my weatherData-hook does not update and returns undefined. What am I doing wrong?

Code:

const renderForecastTable = ({ weatherData }) => (
    <table>
        <thead>
            <th>Tid</th><th>Temperatur</th><th>Vind</th><th>Nederbörd</th>
        </thead>
        <tbody>
        {
        weatherData.Map(hour => 
            <tr>
                <td>{hour.Time}</td><td>{hour.Temp}</td>
                <td>{hour.WindSpeed} m/s {hour.WindDirection} grader</td>
                <td>{hour.AvgPrecipitationIntensity} mm</td>
            </tr>)
            }
        </tbody>
    </table>
)

const Weather = (props) => {
    const [weatherData, setWeatherData] = useState([]);
    const [loading, setLoading] = useState(true);
    const location = useLocation();

    useEffect(() => {
        const getWeather = async () => {
            const response = await fetch(`weather`);
            const json = await response.json();
            setWeatherData(json);
            setLoading(false);
        }
        getWeather();
    }, [])

    return(
        loading ? <></> : renderForecastTable(weatherData)
    )
}

export default Weather;

JSON-response:

[
  {"time":"4/9/2021 8:00:00 AM","temp":"6","windDirection":"216","windSpeed":"8.7","avgPrecipitationIntensity":"0"},
  {"time":"4/9/2021 9:00:00 AM","temp":"5.5","windDirection":"213","windSpeed":"7.9","avgPrecipitationIntensity":"0.2"},
  {"time":"4/9/2021 10:00:00 AM","temp":"4.7","windDirection":"218","windSpeed":"7.1","avgPrecipitationIntensity":"0.3"},
  {"time":"4/9/2021 11:00:00 AM","temp":"5.5","windDirection":"214","windSpeed":"7.3","avgPrecipitationIntensity":"0.3"},
  ...
]
1 Answers

renderForecastTable consumes an argument and attempts to destructure a weatherData property, but it is passed the weatherData state array, renderForecastTable(weatherData). Looks like you also have a typo, weatherData.Map should probably be weatherData.map, with a lowercase "map" function. Since the weatherData is defined as an array I'll assume you meant to simply pass it to the renderForecastTable function.

Consume weatherData array, no destructuring and fix "map" typo.

const renderForecastTable = (weatherData) => (
    <table>
        <thead>
            <th>Tid</th><th>Temperatur</th><th>Vind</th><th>Nederbörd</th>
        </thead>
        <tbody>
        {
        weatherData.map(hour => 
            <tr>
                <td>{hour.Time}</td><td>{hour.Temp}</td>
                <td>{hour.WindSpeed} m/s {hour.WindDirection} grader</td>
                <td>{hour.AvgPrecipitationIntensity} mm</td>
            </tr>)
            }
        </tbody>
    </table>
);

fetch can return rejected promises and there could be errors processing the response, so you should surround the fetching logic in a try/catch.

const Weather = (props) => {
    const [weatherData, setWeatherData] = useState([]);
    const [loading, setLoading] = useState(true);
    const location = useLocation();

    useEffect(() => {
        const getWeather = async () => {
            try {
                const response = await fetch(`weather`);
                const json = await response.json();
                setWeatherData(json);
            } catch(error) {
                // handle any rejected promises or thrown errors processing response
            } finally {
                setLoading(false);
            }
        }
        getWeather();
    }, [])

    return(
        loading ? null : renderForecastTable(weatherData)
    )
}
Related