Reputation: 45
This is a basic weather app that I'm doing to learn Redux. The API does not provide the city name that one searches for, so I must pass it via Redux.
I have the following container:
import React, { Component } from "react";
import { connect } from "react-redux";
class WeatherList extends Component {
renderWeather = cityData => {
const conditions =
cityData.forecast.simpleforecast.forecastday[0].conditions;
const fHigh =
cityData.forecast.simpleforecast.forecastday[0].high.fahrenheit;
return (
<tr>
{/* <td>{cityData.city}</td> */}
<td>{cityData.meta.city}</td>
<td>{conditions}</td>
<td>{fHigh}</td>
</tr>
);
};
render() {
return (
<table className="table table-hover">
<thead>
<tr>
<th>City</th>
<th>Conditions</th>
<th>High (F)</th>
<th>Humidity</th>
</tr>
</thead>
{/* <tbody>{this.props.weather.map(this.renderWeather)}</tbody> */}
<tbody>{this.props.weather.data.map(this.renderWeather)}</tbody>
</table>
);
}
}
const mapStateToProps = ({ weather }) => ({
weather
});
export default connect(mapStateToProps)(WeatherList);
this.props.weather.data.map is throwing an error of "cannot read property map of undefined".
The reducer that is providing the "weather" state is:
import { FETCH_WEATHER } from "../actions/index";
export function WeatherReducer(state = [], action) {
switch (action.type) {
case FETCH_WEATHER:
console.log(action.payload.data);
console.log(action.meta.city);
return { data: [action.payload.data, ...state], meta: action.meta.city };
// return [action.payload.data, ...state];
}
return state;
}
And finally here is the relevant action creator:
import axios from "axios";
const API_KEY = "e95fb12f6c69ae61";
const ROOT_URL = `http://api.wunderground.com/api/${API_KEY}/forecast/q/`;
export const FETCH_WEATHER = "FETCH_WEATHER";
export function fetchWeather(searchData) {
const url = `${ROOT_URL}${searchData.stateName}/${searchData.city}.json`;
const request = axios.get(url);
return {
type: FETCH_WEATHER,
payload: request,
meta: { city: searchData.city }
};
}
You can see from the commented out code that I can get this to work if I only pass along an array to iterate over. But I need to pass more than that in order to get the city name that a person searches for. What can I do to read that first element of the state object, the array, and get rid of the undefined error?
Many thanks for any ideas!
Upvotes: 1
Views: 1921
Reputation: 281646
Since WeatherReducer returns an object with data and meta properties, you must declare it as an object in initialState. Your reducer must look like
const initialState = {
data: [],
meta: ''
}
export function WeatherReducer(state = initialState, action) {
switch (action.type) {
case FETCH_WEATHER:
console.log(action.payload.data);
console.log(action.meta.city);
return { data: [action.payload.data, ...state.data], meta: action.meta.city };
}
return state;
}
The error might come because initially an empty array is returned as the reducer value before fetchWeather
action is triggered and thus this.props.weather.data
would be undefined
. Another thing to follow in such cases is to conditionally use all of such values which can be undefined at certain point of time
Upvotes: 2