me-me
me-me

Reputation: 5809

Understanding combineReducers

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

Answers (3)

Daniel
Daniel

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

zloctb
zloctb

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

Christopher Davies
Christopher Davies

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

Related Questions