Search code examples
javascriptreactjsreact-hooksdispatchreact-context

How to fix dispatch function calling twice each time after clicking button in React?


I have been working on a simple program where I have an array of posts and want to update the individual values of each post object. For this case, I want to update the number of 'likes' a post has when I click on the like button.

Here is the code I have for the reducer:

export function postReducer(state, action) {
    switch(action.type) {
        case 'UPDATE_LIKES':
            return (
                state.map(post => post.id === action.id ? {...post, likes: post.likes+=1, ...post } : {...post })
            )
        default:
            return state   
    }
}

Here is the code I have for the button event calling dispatch when clicked:

export default function PostItem({ post }) {
    const { dispatch } = useContext(PostContext);

    return (
        <div className="container">
            <div className="post-stats">
                <button className="post-like-button" onClick={() => dispatch({
                    type: 'UPDATE_LIKES', id: post.id
                })}>{post.likes}</button>
            </div>
        </div>
    )
}

The issue I'm having is that whenever I click the like button, the 'likes' value increments by 1 only after the first click and then increments by 2 each click afterwards. I want the like button to increment 'likes' by 1 every time I click it. I have tried to figure it out myself and find a solution online but had no luck. All help is appreciated :)


Solution

  • You appear to be mutating state in your reducer by using +=, which may lead to unexpected behavior. Remove this and the unnecessary spread operators and the behavior should be cleaned up.

    export function postReducer(state, action) {
        switch(action.type) {
            case 'UPDATE_LIKES':
                return (
                    state.map(post => post.id === action.id ? {...post, likes: post.likes + 1 } : post)
                )
            default:
                return state   
        }
    }