Hello, everyone!
I'm a beginner of React, Redux and GitHub. I'm doing practice with React + Router + Redux + ImmutableJS. Everything works well until I'm trying to pass array data from one component to another component which use Material-UI grid to show contents in array. And I got this error message with my project.
Uncaught Error: Reducer "ui" returned undefined when handling "CHANGE_ALL_PREVIEW_GOODS" action. To ignore an action, you must explicitly return the previous state.
I know this question had posted by #1378 and #1375. Thanks to these posts , I realized what the error message means literally. But I don't know how to resolve this problem. I can't realize what wrong with my code. Can anyone tell me how to resolve it?
Following are parts of my project.
//Actions
import { createAction } from 'redux-actions';
import {
CHANGE_ALL_PREVIEW_GOODS,
SHOW_ALL_GOODS,
} from '../constants/actionTypes';
export const showItemPicture = (imgSrc) => ({ type: SHOW_ITEM_PICTURE, payload: { imgSrc: imgSrc } });
export const changeAllPreviewGoods = (data) => ({ type: CHANGE_ALL_PREVIEW_GOODS, payload: { data: data } });
//Reducers
import { handleActions } from 'redux-actions';
import { UiState } from '../../constants/models';
import {
SHOW_ITEM_PICTURE,
CHANGE_ALL_PREVIEW_GOODS,
} from '../../constants/actionTypes';
const uiReducers = handleActions({
SHOW_ITEM_PICTURE: (state, {payload} ) => (
state.merge({
'imgSrc': payload.imgSrc,
})
),
CHANGE_ALL_PREVIEW_GOODS: (state, {payload} ) => {
state.merge({
data: payload.data,
})
},
}, UiState);
export default uiReducers;
import { combineReducers } from 'redux-immutable';
import ui from './ui/uiReducers';// import routes from './routes';
const rootReducer = combineReducers({
ui,
});
export default rootReducer;
//Store
import { createStore, applyMiddleware } from 'redux';
import reduxThunk from 'redux-thunk';
import createLogger from 'redux-logger';
import Immutable from 'immutable';
import rootReducer from '../reducers';
const initialState = Immutable.Map();
export default createStore(
rootReducer,
initialState,
applyMiddleware(reduxThunk, createLogger({ stateTransformer: state => state.toJS() }))
);
//Containers - SofaPage
import { connect } from 'react-redux';
import SofaPage from '../../components/SofaPage';
import {
showItemPicture,
changeAllPreviewGoods,
} from '../../actions';
export default connect(
(state) => ({
imgSrc: state.getIn(['ui', 'imgSrc']),
}),
(dispatch) => ({
onShowItemPicture: (src) => (
dispatch(showItemPicture(src))
),
onChangeAllPreviewGoods: (GoodsData) => (
dispatch(changeAllPreviewGoods(GoodsData))
),
}),
(stateProps, dispatchProps, ownProps) => {
const { imgSrc } = stateProps;
const { onChangeAllPreviewGoods } = dispatchProps;
return Object.assign({}, stateProps, dispatchProps, ownProps);
}
)(SofaPage);
//Containers - GoodsPage
import { connect } from 'react-redux';
import GoodsPage from '../../components/GoodsPage';
export default connect(
(state) => ({
data: state.getIn(['ui', 'data']),
}),
(dispatch) => ({
})
)(GoodsPage);
//Constants - GoodsData
const sofaOneTilesData = [
{
img: 'img/sofa/goods/1_1.jpg',
title: 'L style',
author: 'Ben',
featured: true,
},
{
img: 'img/sofa/goods/1_2.jpg',
title: 'Flat style',
author: 'Arya',
},
{
img: 'img/sofa/goods/1_3.jpg',
title: 'Geometric style',
author: 'Takeo',
},
];
export default sofaOneTilesData;
//Components - sofaPage.js
import React from 'react';
import { Link } from 'react-router';
import Paper from 'material-ui/Paper';
import sofaOneTilesData from '../../constants/goodsData.js';
import '../../../css/Animation.css';
const SofaPage = ({
imgSrc,
onShowItemPicture,
onChangeAllPreviewGoods,
}) => (
<div>
<Link to={{
pathname: '/goods',
}}>
<Paper zDepth={5} circle={true}>
<img src="./img/sofa/size1.JPG"
onMouseLeave={ ()=> onShowItemPicture("./img/sofa/sofa_main.JPG") }
onMouseOver={ ()=> onShowItemPicture("./img/sofa/size1.JPG") }
onClick={ ()=> onChangeAllPreviewGoods(sofaOneTilesData) }/>
</Paper>
</Link>
<Paper zDepth={5} circle={true}>
<img src={imgSrc? imgSrc:"./img/home.PNG"}/>
</Paper>
</div>
);
//Components - GoodsPage.js
import React from 'react';
import { Link } from 'react-router';
import {GridList, GridTile} from 'material-ui/GridList';
import IconButton from 'material-ui/IconButton';
import StarBorder from 'material-ui/svg-icons/toggle/star-border';
import Immutable from 'immutable';
const GoodsPage = (props) => (
<div style={styles.root}>
<GridList
cols={2}
cellHeight={200}
padding={1}
style={styles.gridList}
>
{props.data.valueSeq().map((tile) => (
<GridTile
key={tile.img}
title={tile.title}
actionIcon={<IconButton><StarBorder color="white"/></IconButton>}
actionPosition="left"
titlePosition="top"
titleBackground="linear-gradient(to bottom, rgba(0,0,0,0.7) 0%,rgba(0,0,0,0.3) 70%,rgba(0,0,0,0) 100%)"
cols={tile.featured ? 2 : 1}
rows={tile.featured ? 2 : 1}
>
<img src={tile.img} />
</GridTile>
))}
</GridList>
</div>
);
At a quick glance, it looks like your reducer functions are actually returning undefined. In particular:
const uiReducers = handleActions({
SHOW_ITEM_PICTURE: (state, {payload} ) => (
state.merge({
'imgSrc': payload.imgSrc,
})
),
CHANGE_ALL_PREVIEW_GOODS: (state, {payload} ) => {
state.merge({
data: payload.data,
})
},
}, UiState);
Because you're using curly braces for the arrow functions, you can no longer use an implicit return. You need to either put a return in front of state.merge(), or remove the curly braces after the arrows (and possibly just use parentheses instead). Right now, the functions aren't actually returning anything, and are therefore returning undefined.
Oh, I can't believe I misuse {} as () in container. You saved my day, thank you!!
Sure, glad that helped.
As a side note, this sort of question is generally better asked on Stack Overflow. You'll usually get more people looking at the questions, and this is really supposed to be a bug tracker anyway.
OK, Thank you again for everything you're done.
Most helpful comment
At a quick glance, it looks like your reducer functions are actually returning undefined. In particular:
Because you're using curly braces for the arrow functions, you can no longer use an implicit return. You need to either put a
returnin front ofstate.merge(), or remove the curly braces after the arrows (and possibly just use parentheses instead). Right now, the functions aren't actually returning anything, and are therefore returning undefined.