Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux combineReducers not passing state to reducer

In the following code, data (state, action) is not being passed to the reducers by combineReducers. It generates the error below. Probably just a small mistake I'm making. Link to JSFiddle: https://jsfiddle.net/bengrunfeld/1h0t59uf/

import React from 'react'
import { render } from 'react-dom'
import { combineReducers } from 'redux'
import { Constants } from './constants/constants'


const goal = (state = 0, action) => {
  (action.type === Constants.ADD) ?
    state + action.payload:
    state
}

const target = (state = 0, action) => {
  (action.type === Constants.REMOVE)?
    state - action.payload:
    state
}

const reducer = combineReducers({
  goal,
  target
})

const state = 10

const newState = reducer(state, {
  type: Constants.REMOVE,
  payload: 5
})

render(
  <div>
    <p>{newState}</p>
  </div>,
  document.getElementById('main')
)

Error Message

main.bundle.js:28054 Uncaught Error: Reducer "goal" returned undefined during initialization. If the state passed to the reducer is undefined, you must explicitly return the initial state. The initial state may not be undefined.
    at http://localhost:3000/main.bundle.js:28054:13
    at Array.forEach (native)
    at assertReducerSanity (http://localhost:3000/main.bundle.js:28049:25)
    at combineReducers (http://localhost:3000/main.bundle.js:28104:5)
    at Object.<anonymous> (http://localhost:3000/main.bundle.js:13236:42)
    at __webpack_require__ (http://localhost:3000/main.bundle.js:20:30)
    at Object.<anonymous> (http://localhost:3000/main.bundle.js:31673:18)
    at __webpack_require__ (http://localhost:3000/main.bundle.js:20:30)
    at module.exports (http://localhost:3000/main.bundle.js:66:18)
    at http://localhost:3000/main.bundle.js:69:10
like image 772
Ben Avatar asked Oct 18 '22 17:10

Ben


2 Answers

const Constants = {
  REMOVE: "REMOVE",
  ADD: "ADD"
}

const goal = (state = 5, action) => {
  return (action.type === Constants.ADD) ?
    state + action.payload:
    state
}

const target = (state = 5, action) => {
  return (action.type === Constants.REMOVE)?
    state - action.payload:
    state
}

const reducer = Redux.combineReducers({
  goal,
  target
})

const state = {goal: 10, target:5}

const newState = reducer(state, {
  type: Constants.REMOVE,
  payload: 5
})

console.log(newState);

ReactDOM.render(
  <div>
    <p>{newState.goal}</p>
    <p>{newState.target}</p>
  </div>,
  document.getElementById('main')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>


<div id="main"></div>
  1. You need to define an initial state for each of your reducers.
  2. Also you should return a state from your reducer.
like image 153
Anurag Awasthi Avatar answered Oct 20 '22 23:10

Anurag Awasthi


You need to let Redux know what the initial state is going to be.

Either in the reducers themselves (note es6 default argument)

Edit: I just noticed you did not return anything

const goal = (state = 0, action) => {
  return (action.type === Constants.ADD) ?
    state + action.payload:
    state
}

const target = (state = 0, action) => {
  return (action.type === Constants.REMOVE)?
    state - action.payload:
    state
}

Or in the second argument of CreateStore

Here is some comprehensive documentation on that: http://redux.js.org/docs/recipes/reducers/InitializingState.html

like image 32
Imtiaz Avatar answered Oct 21 '22 00:10

Imtiaz