Action does not trigger a reducer in React + Redux

16,165

Solution 1

As Rick Jolly mentioned in the comments on your question, your onSearchPressed() function isn't actually dispatching that action, because addToSaved() simply returns an action object - it doesn't dispatch anything.

If you want to dispatch actions from a component, you should use react-redux to connect your component(s) to redux. For example:

const { connect } = require('react-redux')

class MainView extends Component {
  onSearchPressed() {
    this.props.dispatchAddToSaved();
  }
  render() {...}
}

const mapDispatchToProps = (dispatch) => {
  return {
    dispatchAddToSaved: () => dispatch(addToSaved())
  }
}

module.exports = connect(null, mapDispatchToProps)(MainView)

See the 'Usage With React' section of the Redux docs for more information.

Solution 2

Recently I faced issue like this and found that I had used action import but it has to come from props. Check out all uses of toggleAddContactModal. In my case I had missed toggleAddContactModal from destructuring statement which caused this issue.

import React from 'react'
import ReactDOM from 'react-dom'
import Modal from 'react-modal'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import {
  fetchContacts,
  addContact,
  toggleAddContactModal
} from '../../modules/contacts'
import ContactList from "../../components/contactList";

Modal.setAppElement('#root')

class Contacts extends React.Component {
  componentDidMount(){
    this.props.fetchContacts();
  }
  render(){
    const {fetchContacts, isFetching, contacts, 
      error, isAdding, addContact, isRegisterModalOpen,
      toggleAddContactModal} = this.props;
    let firstName;
    let lastName;
    const handleAddContact = (e) => {
      e.preventDefault();
      if (!firstName.value.trim() || !lastName.value.trim()) {
        return
      }
      addContact({ firstName : firstName.value, lastName: lastName.value});
    };

    return (
      <div>
        <h1>Contacts</h1>
        <div>
          <button onClick={fetchContacts} disabled={isFetching}>
            Get contacts
          </button>
          <button onClick={toggleAddContactModal}>
            Add contact
          </button>
        </div>
        <Modal isOpen={isRegisterModalOpen} onRequestClose={toggleAddContactModal}>
          <input type="text" name="firstName" placeholder="First name" ref={node =>         
 (firstName = node)} ></input>
      <input type="text" name="lastName" placeholder="Last name" ref={node => 
(lastName = node)} ></input>
          <button onClick={handleAddContact} disabled={isAdding}>
            Save
          </button>
        </Modal>
        <p>{error}</p>
        <p>Total {contacts.length} contacts</p>
        <div>
          <ContactList contacts={contacts} />
        </div>
      </div>
    );
  }
}
const mapStateToProps = ({ contactInfo }) => {
  console.log(contactInfo)
  return ({
    isAdding: contactInfo.isAdding,
    error: contactInfo.error,
    contacts: contactInfo.contacts,
    isFetching: contactInfo.isFetching,
    isRegisterModalOpen: contactInfo.isRegisterModalOpen
  });
}

const mapDispatchToProps = dispatch =>
  bindActionCreators(
    {
      fetchContacts,
      addContact,
      toggleAddContactModal
    },
    dispatch
  )

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Contacts)
Share:
16,165
user3802348
Author by

user3802348

Updated on July 18, 2022

Comments

  • user3802348
    user3802348 almost 2 years

    I'm working on a react-redux app and for some reason the action I call does not reach the reducer (in which I currently only have a log statement). I have attached the code I feel is relevant and any contributions would be highly appreciated.

    Action called within function in component:

    onSearchPressed() {
        console.log('search pressed');
        this.props.addToSaved();
    }
    

    actions/index.js:

    var actions = exports = module.exports
    
    exports.ADD_SAVED = "ADD_SAVED";
    
    exports.addToSaved = function addToSaved() {
      console.log('got to ADD_SAVED step 2');
      return {
        type: actions.ADD_SAVED
      }
    }
    

    reducers/items.js:

    const {
      ADD_SAVED
    } = require('../actions/index')
    
    const initialState = {
        savedList: []
    }
    
    module.exports = function items(state = initialState, action) {
        let list
    
        switch (action.type) {
            case ADD_SAVED:
                console.log('GOT to Step 3');
                return state;
            default:
                console.log('got to default');
                return state;
        }
    }
    

    reducers/index.js:

    const { combineReducers } = require('redux')
    const items = require('./items')
    
    const rootReducer = combineReducers({
      items: items
    })
    
    module.exports = rootReducer
    

    store/configure-store.js:

    import { createStore } from 'redux'
    import rootReducer from '../reducers'
    
    let store = createStore(rootReducer)
    

    EDIT: Entire component for onSearchPressed:

    class MainView extends Component {
        onSearchPressed() {
            this.props.addToSaved();
        }
        render() {
            console.log('MainView clicked');
            var property = this.props.property;
    
            return (
                <View style={styles.container}>
                    <Image style={styles.image}
                        source={{uri: property.img_url}} />
                    <Text style={styles.description}>{property.summary}</Text>
                    <TouchableHighlight style = {styles.button}
                            onPress={this.onSearchPressed.bind(this)}
                            underlayColor='#99d9f4'>
                            <Text style = {styles.buttonText}>Save</Text>
                        </TouchableHighlight>
                </View>
            );
        }
    }
    
    module.exports = MainView;
    
  • zok
    zok over 4 years
    I had the same thing a few times and it's annoying as it just fails silently.
  • Temitayo
    Temitayo about 4 years
    when a grown my is almost in tears... destructuring issues, after hours of debugging.
  • Mukul Raina
    Mukul Raina over 2 years
    Thanks so much. This immensely helped!