Action does not trigger a reducer in React + Redux
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)
user3802348
Updated on July 18, 2022Comments
-
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 over 4 yearsI had the same thing a few times and it's annoying as it just fails silently.
-
Temitayo about 4 yearswhen a grown my is almost in tears... destructuring issues, after hours of debugging.
-
Mukul Raina over 2 yearsThanks so much. This immensely helped!