Reputation: 292
Banging my head on this. I've blown through the typical ReactJS and Redux app tuts and am working on my own app. The problem is when using combineReducers() to create a single reducer for the Redux store. I currently have three reducers which, on their own, work fine when when added as the reducer param for createStore(). The first reducer holds all of my actions and is called:
HeaderReducer
import { isActive } from '../actions/HeaderActions';
export const initialButtonState = {
isActive: false,
invertStyles: false
}
export default (state = initialButtonState, action) => {
switch (action.type) {
case 'SET_ACTIVE':
return {
...state,
isActive: action.isActive(state),
invertStyles: action.invertStyles(state),
}
default:
return state
}
}
The second and third reducer are built using ImmutableJS to propagate some dummy content for separate lists. Again, individually these reducers work on their own but do not when combineReducers() combines them. The second reducer file is called:
ListItems
import Immutable from 'immutable';
const messagesList = Immutable.List(['9:00AM - 9:30AM','10:30AM - 11:30AM','11:45AM - 12:30PM','1:00PM - 2:15PM','3:00PM - 4:00PM']);
export default (state = messagesList, action) => {
switch(action.type) {
case 'addItem':
return state.push(action.item)
case 'deleteItem':
return state.filter((item, index) => index !== action.index)
default:
return state
}
}
The third file is called:
QuotesList
import Immutable from 'immutable';
const quotesList = Immutable.List(['Company A: 100.00$','Company B: 200.00$','Company C: 300.00$','Company D: 400.00$','Company E: 500.00$<']);
export default (state = quotesList, action) => {
switch(action.type) {
case 'addItem':
return state.push(action.item)
case 'deleteItem':
return state.filter((item, index) => index !== action.index)
default:
return state
}
}
I have all files exported via an index.js within the reducers folder:
index.js
export { default as HeaderReducers } from './HeaderReducers';
export { default as ListItems } from './MessageList';
export { default as QuotesList } from './QuotesList';
and then called in to create my store in:
Store.js
import { createStore, combineReducers } from 'redux';
import * as reducers from '../reducers';
// import HeaderReducers from '../reducers/HeaderReducers';
// import ListItems from '../reducers/MessageList';
// import QuotesList from '../reducers/QuotesList';
// let reducer = combineReducers({ ListItems: ListItems, quotes: QuotesList})
// export default createStore(ListItems)
const reducer = combineReducers(reducers);
export default createStore(reducer);
Logging the state of the store at launch returns an Object or List, depending on the reducer I use. When I run them through combineReducer(), I get a single Object returned holding each reducer together. What breaks immediately is a .map function I have setup in ListItems.js
import React from 'react';
import { connect } from 'react-redux';
import NewItem from './NewItem';
import { addItem, deleteItem } from '../../../actions/HeaderActions';
const ListItems = ({ListItems, dispatch}) => (
<div>
<ul>
{ListItems.map((ListItem, index) => <li><span key={index}> {ListItem} <button onClick={e => {
dispatch(deleteItem(index))
}}>X</button></span></li>)}
</ul>
<NewItem />
</div>
)
function mapStateToProps(ListItems) {
return {
ListItems,
}
}
export default connect(mapStateToProps)(ListItems)
Console shows "_ListItems.map is not a function". I've gone through and tried editing the mapStateToProps return value but I'm grasping at straws. Thanks for reading this. Any help is definitely appreciated.
Upvotes: 5
Views: 1083
Reputation: 6228
Combine reducers does not work with Immutable structures, there needs to be reconciliation to detect changes, you can use redux-immutable:
import {
combineReducers
} from 'redux-immutable';
import {
createStore
} from 'redux';
const initialState = Immutable.Map();
const rootReducer = combineReducers({});
const store = createStore(rootReducer, initialState);
I have recently used this in one of the projects at work, however looking at your code I would say it is generally a bad idea to have both immutable and mutable states, you should keep it with simple structures or full immutable.
Even though ImmutableJS is great, the fact that this is not directly integrated into the language (it is a user library) can lead to very verbose code bases, another alternative is to use Object.freeze to prevent mutation to your state and that way you can keep the regular combine reducers from redux.
Upvotes: 1
Reputation: 191976
combineReducers doesn't support immutable. Try redux-immutable combineReducers instead.
Upvotes: 3