Reputation: 5809
New to react and redux so playing around with some very simple code to see how it all works. When I try passing in a combineReducers method to a redux store then I get an error. If I remove the combinedReducers and pass the reducer in directly to the store all works fine.
let store = createStore(rootReducer);
Error
Uncaught Error: Objects are not valid as a React child (found: object with keys {reducer}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of App.
Why do I get an error when I use combineReducers ? What if I wanted to add more reducers I presume thats what combineReducers is there for ?
main.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, combineReducers } from 'redux';
import App from './components/app';
let reducer = (state=0, action) => {
switch (action.type) {
case 'INCREASE':
return state+1
case 'DECREASE':
return state-1
default: return state
}
}
const rootReducer = combineReducers({
reducer:reducer
});
let store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.querySelector('.container'));
//app.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
class App extends Component {
render() {
let {number, increase, decrease} = this.props
return(
<div>
<div>{number}</div>
<button onClick={e=>increase()}>+</button>
<button onClick={e=>decrease()}> - </button>
</div>
);
}
}
let mapStateToProps = state => ({
number: state
})
let mapDispatchToProps = dispatch => ({
increase: () => dispatch({type: 'INCREASE'}),
decrease: () => dispatch({type: 'DECREASE'})
});
export default connect(mapStateToProps, mapDispatchToProps)(App);
Upvotes: 20
Views: 33451
Reputation: 15413
I believe you could have also done:
const INITIAL_STATE = { number: 0 };
export default (state = INITIAL_STATE, action) => {
switch (action.type) {
case 'INCREASE':
return state+1
case 'DECREASE':
return state-1
default: return state
}
};
Upvotes: 0
Reputation: 11177
https://redux.js.org/docs/basics/Reducers.html
import { combineReducers } from 'redux'
const todoApp = combineReducers({
visibilityFilter,
todos
})
export default todoApp
Note that this is equivalent to:
export default function todoApp(state = {}, action) {
return {
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
todos: todos(state.todos, action)
}
}
You could also give them different keys, or call functions differently. These two ways to write a combined reducer are equivalent:
const reducer = combineReducers({
a: doSomethingWithA,
b: processB,
c: c
})
function reducer(state = {}, action) {
return {
a: doSomethingWithA(state.a, action),
b: processB(state.b, action),
c: c(state.c, action)
}
}
And don't forget connect each parts
@connect(state => ({
reducerName: state[partStoreName]
}))
Upvotes: 9
Reputation: 4551
Combine reducers takes a hash of reducers and returns a reducer. The resulting reducer represents an object of the same shape as the hash.
So, a call like this:
combineReducers({ name: nameReducer})
Would produce a state object that might look something like this:
{ name: 'Joe Shmo' }
In your example, you are producing a global state tree that looks like this:
{ reducer: 0 }
But you are trying to pull a property called number
out of this in your mapStateToProps
.
If you change your reducer declaration to look like this:
const number = (state=0, action) => {
switch (action.type) {
case 'INCREASE':
return state+1
case 'DECREASE':
return state-1
default: return state
}
}
const rootReducer = combineReducers({
number
});
Then change your mapStateToProps
to look like this:
const mapStateToProps = ({number}) => ({number});
Your code should start working.
Upvotes: 14