React Redux : Action creator not calling reducer

kennedy picture kennedy · Mar 12, 2017 · Viewed 15.8k times · Source

My action creator is not calling my reducer. Any help will be much appreciated.

types.js

export const SELECTED_FOOD = 'selected_food';

index.js (action creator / action)

import {
  SELECTED_FOOD
} from './types';

export function selectedFood({data}) {
console.log('SELECTED_FOOD **********************',data);
  return({
    type: SELECTED_FOOD,
    payload: data
  });
}

Output from console.log in action creator

Object {_id: "18240", description: "Croissants, apple", score: 0.75, fields: Object}

selected_food_reducer.js

import {
SELECTED_FOOD

} from '../actions/types';

export default function(state = [], action) {
 switch(action.type) {
  case SELECTED_FOOD:
    console.log('Selected Food Reducer *************', state);
    return  action.payload ;
}

return state;
}

EDIT component failing to call dispatch.

I should have added this on my initial post, it appears there is something wrong in how dispatch is called. ESLint is flagging dispatch on line 3 for defined but never used.

import React from 'react';
import { connect } from 'react-redux';
import { dispatch } from 'react-redux';
import { selectedFood } from '../actions/index';

class TableRow extends React.Component {
  render() {
    const {
      data
    } = this.props;


    console.log('PROPS TableRow', this.props);

    const row = data.map((data) =>
    <tr onClick={() => selectedFood({data})}>
      <td key={data.description}>{data.description}</td>
      <td key={data.id}>{data.fields.nutrients[0].amountPer100G}</td>
      <td key={data.id}>{data.fields.nutrients[1].amountPer100G}</td>
      <td key={data.id}>{data.fields.nutrients[4].amountPer100G}</td>
    </tr>
    );
    return (
      <tbody>{row}</tbody>
    );
  }
}

const  mapStateToProps = (state) => {
  return {
    selectedFood: state.selectedFood
  }
}


const mapDispatchToProps = (dispatch) => {
  console.log('IN mapDispatchToProps')
  return {
    onClick: ({data}) => {
      dispatch(selectedFood({data}))
    }
  }
}

export default connect(mapStateToProps, mapDispatchToProp)(TableRow);

Answer

alek kowalczyk picture alek kowalczyk · Mar 12, 2017

The action creator does not call the reducer. It is what it is, nothing more, it creates an action - that is, an object with the action type and the payload for that action.

You need to dispatch an action, to force redux to call the reducer, and that is the place where you use your action creator, that is:

import { Dispatch } from "redux";
import { selectedFood } from "./actions";
Dispatch(selectedFood({type:"hamburger"}));

that should call the reducer, however mostly you'll not call the Dispatch directly, rather in your mapDispatchToProps method used to connect your react component to the redux store.

There are plenty of sample how to use react-redux to use above map functionality, so I would suggest to read into it, and to read how redux works.

====== EDIT after question updated =========

So firstly dispatch from import is not used and ESLint is right telling it, you don't need that import since in:

const mapDispatchToProps = (dispatch) => {
  console.log('IN mapDispatchToProps')
  return {
    onClick: ({data}) => {
      dispatch(selectedFood({data}))
    }
  }
}

you don't call dispatch from your import only from the argument, it's passed to your mapDispatchToProps by the connect function.

Then this is just plain wrong:

<tr onClick={() => selectedFood({data})}>

you imported an action creator which is called on click of table row, that is an action definition is created by the action creator, and that's it. Your code does exactly what you wrote.

The mapDispatchToProps function does what the name suggests - it maps dispatch functions to props of your component.

So it should be:

<tr onClick={() => this.props.onClick({data})}>

and that should dispatch the action and work.

However I would strongly suggest to take some courses or read more about react, redux and react-redux, because your code samples and the question itself suggest, that you are just trying to get something to work, without the basic understanding how it works, and even how javascript works. Sorry for that comment but that's how it looks like.