Reputation: 696
I'm struggling with react-redux thing quite a lot of hours. I want to show to user <Alert />
when isVisible
value is true. I'm still don't understand well architecture of redux. So, I'm trying to pass value to reducer but it doesn't work. What I'm doing wrong?
Alert component:
export default () => {
return (
<div className="alert alert-warning">
<strong>Warning!</strong> Indicates a warning that might need attention.
</div>
);
};
Weather container:
renderWeather(cityData) {
const name = cityData.city.name;
const temps = _.map(cityData.list.map(weather => weather.main.temp), (temp) => temp - 273);
return (
<tr key={name}>
<td><Chart data={temps} color="orange" units="C" /></td>
</td>
</tr>
)
}
render() {
return (
<div>
{this.props.isVisible ? null : <Alert /> }
<table className="table table-hover">
<thead>
<tr>
<th>City</th>
<th>Temperature (C)</th>
</tr>
</thead>
<tbody>
{this.props.weather.map(this.renderWeather)}
</tbody>
</table>
</div>
)
}
}
function mapStateToProps({ weather, isVisible }) {
return { weather, isVisible };
}
export default connect(mapStateToProps)(WeatherList);
Index reducer:
const rootReducer = combineReducers({
weather: WeatherReducer,
isVisible: WeatherReducer
});
export default rootReducer;
Reducer:
export default function (state = [], action) {
switch (action.type) {
case FETCH_WEATHER:
return [...state, action.payload];
case FETCH_WEATHER_ERROR:
return {state, isVisible: false}
}
return state;
}
Action:
export function fetchWeather (city) {
const url = `${ROOT_URL}&q=${city}`;
return (dispatch) => {
axios.get(url);
.then(({data}) => {
dispatch({type: FETCH_WEATHER, payload: data});
})
.catch((error) => {
dispatch({type: FETCH_WEATHER_ERROR, payload: error});
});
};
}
Upvotes: 1
Views: 5410
Reputation: 124
Split code into smaller reducers:
const rootReducer = combineReducers({
weather: weatherReducer,
isVisible: isVisibleReducer
});
export default rootReducer;
// reducers:
const weatherReducer = (state = [], action) => {
if (action.type === FETCH_WEATHER) {
return action.payload; // data object
}
if (action.type === FETCH_WEATHER_ERROR) {
return action.payload; // error object
}
return state;
};
const isVisibleReducer = (state = false, action) => {
if (action.type === FETCH_WEATHER) {
return true;
}
if (action.type === FETCH_WEATHER_ERROR) {
return false;
}
return state;
};
export { weatherReducer, isVisibleReducer };
Now each reducer function has own zone of control.
In your reducer you have mixed type of state. Default is an empty array []
, but later you have returned an object ({state, isVisible: false}
). Don't do that.
You also reduce weather
and isVisible
nodes of state by the same WeatherReducer
. It's not correct, because the logic of modifying this nodes is different.
Upvotes: 1
Reputation: 146
You have to decide if your state need to be an array or an object. From your reducer, initial state is an empty array, but if FETCH_WEATHER
is dispatched it returns array and FETCH_WEATHER_ERROR
returns object.
I suggest you modify combineReducers as well, there is no point passing same reducer to different properties in root state.
const rootReducer = combineReducers({
weather: WeatherReducer,
});
is enough. Lets assume your state is an Object, with isVisible
and weather
properties. So your reducer will become.
export default function (state = {isVisible:false, weather:[]}, action)
{
switch (action.type) {
case FETCH_WEATHER:
return Object.assign({}, {weather: action.payload, isVisible:false})
case FETCH_WEATHER_ERROR:
return Object.assign({}, {weather:null, isVisible:true})
}
return state;
}
And finally if you want to show when isVisible is true you have to
{this.props.isVisible ? <Alert /> : null }
Upvotes: 2
Reputation: 154
you need an Action that will change the isVisible eq
function changeVisible() {
return {
type: FETCH_WEATHER_ERROR
}
}
and
case FETCH_WEATHER_ERROR:
return {...state, isVisible: true}
Upvotes: 0
Reputation: 741
{this.props.isVisible ? null : <Alert /> }
should be replace by {this.props.isVisible ? <Alert /> : null }
because when this.props.isVisible is true then only will be visible but you are doing it wrong..
Hoped it helped
Upvotes: 0