Search code examples
javascripthtmlreactjsredux

Redux connect() higherordercomponent not working while i pass action creater throwing mapDispatchToProps


Action creater not working in react-redux while using the mapDispatchToProps function return object to pass in connect HOC. It working while passing Action creater directly in connect HOC something below. Not able to understand the difference.

Not Working:

const mapDispatchToProps = () => {
        return {
            increment,
            decrement
        }
    }
   
const WrappedCounter = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Counter);

Working:

const WrappedCounter = ReactRedux.connect(mapStateToProps, {
        increment,
        decrement
    })(Counter);

Detailed Code:

<script type="text/babel" data-plugins="proposal-class-properties" data-presets="env,react">
// Action Creators - You don't need to change these
const increment = () => ({ type: 'increment' });
const decrement = () => ({ type: 'decrement' });

const Counter = (props) => {
    return (
        <div>
            <button className="increment" onClick={props.increment}>Increment</button>
            <button className="decrement" onClick={props.decrement}>Decrement</button>
            Current Count: <span>{props.count}</span>
        </div>
    );
};

const mapStateToProps = (state) => {
    return { count: state.count }
}

const mapDispatchToProps = () => {
    return {
        increment,
        decrement
    }
}

const WrappedCounter = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(Counter);

// Only change code *before* me!
// -----------

const store = Redux.createStore(Redux.combineReducers({
    count: (count = 0, action) => {
        if (action.type === 'increment') {
            return count + 1;
        } else if (action.type === 'decrement') {
            return count - 1;
        } else {
            return count;
        }
    }
}));

ReactDOM.render(
    <ReactRedux.Provider store={store}>
        <WrappedCounter />
    </ReactRedux.Provider>, 
    document.querySelector('#root')
);

Solution

  • There are two valid syntaxes for writing mapDispatchToProps. What you have here is kind of a combination of the two, but it's not correct for either one.

    Function Syntax

    The "classic" (largely outdated) form of mapDispatchToProps is a function which takes dispatch as an argument and returns props of your component. Those props are just normal functions so they need to make the dispatch call themselves.

    It is very verbose and I don't recommend this:

    const mapDispatchToProps = (dispatch) => {
      return {
        increment: () => dispatch(increment()),
        decrement: () => dispatch(decrement())
      }
    }
    

    Object Syntax

    The simpler way to define mapDispatchToProps is with the object shorthand notation. Here, you return a dictionary of action creator functions and react-redux handles binding them to dispatch automatically.

    That looks like this:

    const mapDispatchToProps = {
      increment,
      decrement
    }
    

    When using this syntax, mapDispatchToProps is not a function, it's just an object.

    In your semi-working solution where you defined mapDispatchToProps as a function and then called the function with connect(mapStateToProps, mapDispatchToProps())(Counter), you using this syntax but with an extra step. You defined a function that returns the object. Then called the function to get the object.

    Just Use Hooks

    The most modern way of writing this is to ditch the connect higher-order component entirely and use the react-redux hooks.

    const Counter = () => {
        const count = useSelector((state) => state.count);
        const dispatch = useDispatch();
    
        return (
            <div>
                <button className="increment" onClick={() => dispatch(increment())}>Increment</button>
                <button className="decrement" onClick={() => dispatch(decrement())}>Decrement</button>
                Current Count: <span>{props.count}</span>
            </div>
        );
    };