Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Redux - reducer not getting called

I'm trying to learn Redux. I followed an online tutorial and used their example and it worked fine. Then I made another small test app and it worked fine. Now I'm trying another small test app and I'm stuck on this error and have no idea why.

The app is simply a input box and a button, and when you click the button it adds whatever's in the box to a list that is displayed below.

However, the reducer isn't updating the state. I've looked at the common problems that cause this and can't seem to find those errors in mine, my reducer doesn't change the state and I've bound the dispatch and so on. Maybe I've just mispelled something somewhere (or something small and stupid like that) but I just can't get it working.

So I tried to change it so that it just displays whatever you type in the box below and it STILL doesn't work. Anyone know why the reducer isn't activating?

index.js (main)

import 'babel-polyfill';
import React from 'react';
import ReactDOM from 'react-dom';
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import promise from 'redux-promise';
import createLogger from 'redux-logger';
import allReducers from './reducers';
import App from './components/App';

const logger = createLogger();
const store = createStore(
    allReducers,
    applyMiddleware(thunk, promise, logger)
);

ReactDOM.render(
    <Provider store={store}>
      <App />
    </Provider>,
    document.getElementById('root')
);

App.js

import React from 'react';
import NameList from '../containers/name-list.js'
import Input from '../containers/input.js'

const App = () => (
  <div>
    <Input />
    <hr />
    <NameList />
  </div>
);

export default App;

index.js (action)

export const addName = (name) => {
    return {
        type: 'NAME_ADDED',
        payload: name
    }
};

reducer-add-name.js

export default function (state = null, action) {
    switch (action.type) {
        case 'NAME_ADDED':
            return action.payload;
            break;
    }
    return state;
}

index.js (reducer combiner)

import {combineReducers} from 'redux';
import AddNameReducer from './reducer-add-name';


const allReducers = combineReducers({
    nameList: AddNameReducer
});

export default allReducers

input.js

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';
import {addName} from '../actions/index'

class Input extends Component {
  render() {
    return(
      <div>
        <input id='name-input' />
        <button id='add-name-button' onClick={() => addName(document.getElementById('name-input').value)}>Add name</button>
      </div>
    );
  }
}

function mapStateToProps(state) {
  return {
    nameList: state.nameList
  };
}

function matchDispatchToProps(dispatch) {
  return bindActionCreators({addName: addName}, dispatch);
}

export default connect(mapStateToProps, matchDispatchToProps)(Input);

name-list.js

import React, {Component} from 'react';
import {bindActionCreators} from 'redux';
import {connect} from 'react-redux';

class NameList extends Component {

  getNameList() {
    //This is where I'll loop through this.props.nameList and build the list of elements
    return this.props.nameList;
  }

  render() {
    return(
      <div>Current list : {this.getNameList()}</div>
    );
  }
}

function mapStateToProps(state) {
  return {
    nameList: state.nameList
  };
}

export default connect(mapStateToProps)(NameList);

Thanks for any help!

like image 725
Jayce444 Avatar asked Oct 29 '16 08:10

Jayce444


People also ask

Does Redux call all reducers?

One frequently asked question is whether Redux "calls all reducers" when dispatching an action. Since there really is only one root reducer function, the default answer is "no, it does not".

What does combineReducers do in Redux?

The combineReducers helper function turns an object whose values are different reducing functions into a single reducing function you can pass to createStore .

What is the difference between actions and reducers Redux?

Reducers: As we already know, actions only tell what to do, but they don't tell how to do, so reducers are the pure functions that take the current state and action and return the new state and tell the store how to do.


3 Answers

I think your action hasn't been dispatched.

In your input.js On button tag, change

onClick={() => addName(document.getElementById('name-input').value)}

to

onClick={() => this.props.addName(document.getElementById('name-input').value)}

Thing is action should be passed through mapDispatchToProps and 'bindActionCreators(actions, dispatch)' will wrap your action with 'dispatch', and pass through your component via props 'addName'. (as defined in your mapDispatchToProps)

An action alone is like a bullet (just return object) you will need something to fire it (dispatch)

In your case

import {addName} from '../actions/index' <--- a bullet

has been declared and your onClick, without dispatch, it would only return a mere object, not dispatching it to reducer.

addName() // <--- Just a bullet

But

this.props.addName() // <--- bullet with a gun

is from mapDispatchToProps / bindActionCreators... it has dispatch() wrapped around, that is the one we would use.

like image 57
Doppio Avatar answered Nov 15 '22 20:11

Doppio


Not the OP's question but for people who just searched Google for "reducer not getting called", make sure you call your action creator:

dispatch(action())

not

dispatch(action)

You have to pass in the action, not the action creator. With useSelect in Redux Toolkit I usually don't have parens in the arg so I forgot to put the parents in the call to dispatch.

like image 21
Alexander Taylor Avatar answered Nov 15 '22 19:11

Alexander Taylor


This happened to me today.

I forgot to add my new action to my destructured props in React while using the class method

const { newAction } = this.props
like image 35
Emmanuel Orozco Avatar answered Nov 15 '22 20:11

Emmanuel Orozco