Tylerlee12 Tylerlee12 - 3 months ago 9
React JSX Question

Why is Redux not dispatching my action to the reducer?

In my app React Redux app, I'm trying to update state whenever the user selects a new state of residence (e.g. Alabama) from a dropdown. However, nothing seems to be happening. In my Redux dev tools, Redux state doesn't appear to be changing when I change the item in the dropdown menu. Here is my code:

actionTypes.js

export const UPDATE_STATE_OF_RESIDENCE = 'UPDATE_STATE_OF_RESIDENCE';


accountDetailsActions.js

import * as types from '../constants/actionTypes';

export function updateStateOfResidence(stateOfResidence) {
return {type: types.UPDATE_STATE_OF_RESIDENCE, stateOfResidence};
}


AccountDetailsAccordionContainer.js

import React, {PropTypes} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import * as actions from '../actions/accountDetailsActions';
import AccountDetailsAccordion from '../components/AccountDetailsAccordion';

export const AccountDetailsAccordionContainer = (props) => {
return (
<AccountDetailsAccordion
updateStateOfResidence={actions.updateStateOfResidence}
/>
);
};

AccountDetailsAccordionContainer.propTypes = {
actions: PropTypes.object.isRequired,
};

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

function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators(actions, dispatch)
};
}

export default connect(
mapStateToProps,
mapDispatchToProps
)(AccountDetailsAccordionContainer);


AccountDetailsAccordion.js

import React from 'react';
import GeneralSelect from './common/GeneralSelect';
import States from '../data/State';
import AccountTypes from '../data/AccountType';

// Since this component is simple and static, there's no parent container for it.
const AccountDetailsAccordion = (props) => {
return (
<div>
<h3 id="accountDetailsPanel">SELECT STATE AND ACCOUNT TYPE</h3>
<div id="accountDetailsContainer" className="inner-content" style={{paddingTop: 10}}>
<div>
<div id="accountOwnerSignerInfo" style={{float:"left", paddingRight:15}}>
</div>
<div id="accountAttributes" style={{float:"left"}}>
<div id="stateSelectionContainer" style={{paddingLeft:5+"em"}}>
<div className="input-label">Client's State of Residency: (required)</div>
<GeneralSelect id="stateSelect" classString="account-details-field" items={States} defaultString="Select a State" onChange={props.updateStateOfResidence} />
</div>
</div>
</div>
</div>
</div>
);
};

AccountDetailsAccordion.propTypes = {
updateStateOfResidence: React.PropTypes.func.isRequired
};

export default AccountDetailsAccordion;


GeneralSelect.js

import React from 'react';

const GeneralSelect = (props) => {
const handleChange = (event) => {
props.onChange(event.target.value);
};

return (
<select id={props.id} className = {props.classString} style={props.styleObject} onChange={handleChange}>
<option value="nothingSelected" defaultValue>{props.defaultString}</option>
{
props.items.map((item) => {
//if the item has an enabled property, let's use it. otherwise, render the item no matter what
return (
<option key={item.id} value={item.id}>{item.name}</option>
);
})
}
</select>
);
};

GeneralSelect.propTypes = {
id: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number
]),
classString: React.PropTypes.string,
styleObject: React.PropTypes.object,
defaultString: React.PropTypes.string,
items: React.PropTypes.oneOfType([
React.PropTypes.array,
React.PropTypes.object
]).isRequired,
onChange: React.PropTypes.func
};

export default GeneralSelect;


accountDetailsReducer.js

import {UPDATE_STATE_OF_RESIDENCE} from '../constants/actionTypes';
import objectAssign from 'object-assign';
import initialState from './initialState';

export default function accountDetailsReducer(state = initialState, action) {
let newState;
console.log(action.type);
switch (action.type) {
case UPDATE_STATE_OF_RESIDENCE:
console.log(action);
return objectAssign({}, state, {stateOfResidence: action.stateOfResidence});

default:
console.log('default');
return state;
}
}


index.js - my root reducer:

import { combineReducers } from 'redux';
import accountDetails from './accountDetailsReducer';

const rootReducer = combineReducers({
accountDetails
});

export default rootReducer;


initialState.js:

export default {
accountDetails: {
stateOfResidence: '',
accountType: '',
accountNumber: ''
}
};


And finally, here is what my state looks like in the Redux dev tools:

enter image description here

What am I doing wrong?

Answer

You have a typo.

updateStateOfResidence={props.actions.updateStateOfResidence}

instead of

updateStateOfResidence={actions.updateStateOfResidence}

The reason why it fails silently is because you are using the vanilla actions that it is not bounded to the dispatcher, instead of the bounded one provided by connect() in props.

Comments