Reputation: 442
I am new to redux and trying to build a simple app in which users can vote on their favourite front end framework. I want to have a workflow where the user clicks to cast a vote, this dispatches a vote action. After the vote action a different action is fired to calculate the percentages of total votes for each framework.
My store/reducer setup looks as such:
const combinedReducers = combineReducers({
"votes": votesReducer,
"currentPercentages": currentPercentageReducer,
"pastPercentages": pastPercentageReducer
});
let store = createStore(combinedReducers, applyMiddleware(thunk));
store.subscribe(() => {
console.log('store state is', store.getState())
})
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
My click handlers fire the intital "cast vote" action which in turn fires the "calculate percentages" action. They look like this:
//click handlers
votedAngular(){
this.props.dispatch(castVote('angular'));
}
votedReact(){
this.props.dispatch(castVote('react'));
}
votedVue(){
this.props.dispatch(castVote('vue'));
}
The action creators:
const voteAction = (framework) => {
return {
type: "VOTE",
payload: framework
}
}
const updateCurrentPercentages = (voteState) => {
return {
type: "UPDATE_CURRENT_PERCENTAGES",
payload: voteState
}
}
export const castVote = (framework) => (dispatch, getState) => {
dispatch(voteAction(framework));
dispatch(updateCurrentPercentages(getState().votes)); //this does pass in current vote state correctly
}
Finally - the heart of the problem. My reducer which handles updating the current vote percentages.
export function currentPercentageReducer(state=intitialPercentages, action){
switch (action.type){
case "UPDATE_CURRENT_PERCENTAGES":
let totalVotes = action.payload.angular + action.payload.react + action.payload.vue;
//totalVotes, and individual percentage calculations are
//all console.logged correctly.
//EX. if there is one vote for each of the three frameworks
//I get totalVotes = 3, pctAngular = 1/3, pctReact = 1/3,
//pctVue = 1/3
console.log('totalVotes', totalVotes)
console.log('pctAngular', action.payload.angular + ' / ' + totalVotes);
console.log('pctReact', action.payload.react + ' / ' + totalVotes);
console.log('pctVue', action.payload.vue + ' / ' + totalVotes);
let pctAngular = Math.floor(action.payload.angular / totalVotes) * 100;
let pctReact = Math.floor(action.payload.react / totalVotes) * 100;
let pctVue = Math.floor(action.payload.vue / totalVotes) * 100;
//as soon as I vote for two or more different options
//the console.log below always returns 0,0,0
console.log(pctAngular, pctReact, pctVue);
//returns the correct state when you only vote for one
//option, but when you vote for two or more returns
// {angular:0, react:0, vue:0}
return Object.assign({}, state, {
angular: pctAngular,
react: pctReact,
vue: pctVue
});
default:
return state
}
}
Could someone please explain what is happening here?
Upvotes: 0
Views: 265
Reputation: 396
What I suspect is happening here is that Math.floor
always returns 0 for fractions. On your first vote you get Math.floor(1/1) = 1
but on your next vote you might get Math.floor(1/2) = 0
. Can you confirm that if your first two votes are for the same framework you see correct results? Try using Math.round(num * 100) / 100
instead.
Upvotes: 2