I am new to redux and am writing a simple voting front end which allows the user to vote on their favourite framework (Angular, React, Vue). When a user clicks on a framework they would like to vote for, I intend to increment the votes in the store by one.
I'm using combineReducers
and connect
to facilitate this. However, after each click, the state is always one vote behind. After one vote the state is at 0. After 2 clicks, the vote state is at 1, etc.
Here is my index.js
file wherein I create my store and render the app
//index.js
const combinedReducers = combineReducers({
"votes": votesReducer,
"currentPercentages": currentPercentageReducer,
"pastPercentages": pastPercentageReducer
});
let store = createStore(combinedReducers);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
Here is my action
export function voteAction(framework){
return {
type: "VOTE",
payload: framework
}
}
Below is the relevant reducer for updating the vote state
const initialVoteState = { angular: 0, react: 0, vue: 0 };
export function votesReducer(state=initialVoteState, action){
switch(action.type){
case "VOTE":
if (action.payload === 'angular'){
return Object.assign({}, state, {
angular: state.angular + 1
});
} else if (action.payload === 'react'){
return Object.assign({}, state, {
react: state.react + 1
});
} else {
return Object.assign({}, state, {
vue: state.vue + 1
});
}
default:
return state;
}
}
Finally, here is the component I have which has the click handler to facilitate casting a vote and updating the state accordingly.
@connect(state => {
return {
votes: {
angular: state.votes.angular,
react: state.votes.react,
vue: state.votes.vue
},
currentPercent: {
angular: state.currentPercentages.angular,
react: state.currentPercentages.react,
vue: state.currentPercentages.vue
},
pastPercent: {
angular: state.pastPercentages.angular,
react: state.pastPercentages.react,
vue: state.pastPercentages.vue
}
}
})
export default class InfoArea extends Component {
constructor(props){
super(props);
this.votedAngular = this.votedAngular.bind(this);
this.votedReact = this.votedReact.bind(this);
this.votedVue = this.votedVue.bind(this);
}
votedAngular(){
this.props.dispatch(voteAction('angular'));
console.log(this.props.votes.angular);
//the log above will output 0 after the first vote is cast, 1
after the second vote is cast etc. Why is this the case? Should
it not be set to the correct value here since the action has
already been dispatched?
}
votedReact(){
this.props.dispatch(voteAction('react'));
}
votedVue(){
this.props.dispatch(voteAction('vue'));
}
render(){
return (
<div className="info-container">
<img
style={{"marginTop":"25px"}}
className="app-img"
src={require("../../public/brainbulb.svg")}>
</img>
<h2 className="wide">What is your favourite front-end framework in 2017?</h2>
<h4 style={{"marginTop": "0"}}>Click an image below to vote!</h4>
<div className="row">
<div className="images-container">
<img
onClick={this.votedAngular}
className="framework-logo"
src={require("../../public/angular.png")}>
</img>
<img
onClick={this.votedReact}
className="framework-logo"
src={require("../../public/react.png")}>
</img>
<img
onClick={this.votedVue}
className="framework-logo"
src={require("../../public/vue.png")}
></img>
</div>
</div>
</div>
);
}
}
Also worth noting that when I cast a vote and view my store state in the browser console it is accurate. Yet, my component remains one vote behind. Any help would be greatly appreciated.