MergeProps in Redux

MergeProps in Redux
0.0 0

#1

I’m trying to write a simple toggle button for starting an application and need to access data from the Redux state in the mapDispatchToProps, so I am using mergeProps, as a result. The basic idea is this: when clicked, the component retrieves the gameStarted property from the Redux store and in mapDispatchToProps modifies the gameStarted property (replacing it with its opposite) by dispatching the startGame action. Because I need to access gameStarted from the current state I am merging props from dispatch and from state in mergeProps, but when I do so I get an infinite loop, where the action is dispatched without the component being clicked which in turn causes the component to get re-rendered, dispatching the action again and so on. How do I stop this from happening?

This is my code:

//action
export const startGame = (started) => ({ type: START, gameStarted: started });

//reducer
const initialState = {
  gameStarted: false,
};

const drumReducer = (state=initialState, action) => {
  switch (action.type) {
    case START:
      console.log('reducer start', action.gameStarted);
      return Object.assign({}, state, { gameStarted: !action.gameStarted });
    default:
      return state;
  }
};

//component
class Button extends Component {

  render() {
    return (
      <div className="start-container" onClick={this.props.starts}></div>
    );
  }
}

const mapStateToProps = (state) => ({ gameStarted: state.gameStarted });

const mapDispatchToProps = (dispatch) => ({
  dispatchStarts: (gameStarted) => dispatch(startGame(gameStarted)),
});

const mergeProps = (propsFromState, propsFromDispatch) => (
    {
      ...propsFromState,
      ...propsFromDispatch,
      starts: propsFromDispatch.dispatchStarts(propsFromState.gameStarted),
    }
  );

export default connect(mapStateToProps, mapDispatchToProps, mergeProps)(Button);

#2

I’m not really sure why you’re infinitely looping, but onClick expects a function, and it seems you’re setting the starts prop to the result of a function. Which is probably being called every time the button renders.

So my first instinct is to make that prop a function

starts: () => propsFromDispatch.dispatchStarts(propsFromState.gameStarted),

or make the onClick a function

onClick={() => this.props.starts }

#3

Thanks, that was it. Probably the dispatch was being called immediately on render. Come to think of it, I have encountered this problem in vanilla JavaScript. I was being so focused on Redux that I forgot about simple issues like these.