Actions not dispatched to reducers, WHY!?

Hi campers, I am working on the Simon game.

https://gameofsimon.netlify.com/
https://github.com/shimphillip/simon-game

Having major trouble figuring out why actions are not being dispatched to reducers.

My other actions such as “TOGGLE_POWER” and “START_GAME” get dispatched just fine but my “ADD_USER_INPUT” doesn’t.

Please take a look at my Pads.js, PadsActions.js and GameReducer.js.

Thank you for your inputs!

I think you are not passing dispatch() to your actions.
You are indeed creating an action object but nothing in your structure is passing the dispatch method to your actions.

I think that if you want to keep an Object structure you need to rely on bind action creator.

Imho it’s easier to implement a mapDispatchToProp function as second argument:

const mapStateToProps = state => {
  return {
    gameReducer: state.gameReducer
  };
};

const mapDispatchToProps = dispatch => {
  return: {
     onAction: () => dispatch(myAction),
  }
}

export default connect( mapStateToProps, mapDispatchToProps)(Pads);

note: try to look for a this.props.dispatch is not defined error :slight_smile:

Reference: react-redux connect

Hi @Marmiz thanks for your input! but I am already dispatching my actions in PadsActions.js like this.

And I am calling addUserInput in Pads.js

export const addUserInput = padNumber => {
  console.log("action", padNumber);
  return (dispatch) => {
    dispatch({
      type: ADD_USER_INPUT,
      payload: padNumber
    })
  }
}

So I think the direction you gave me is just another way of dispatching actions and I confirmed it still does the same thing. It calls my action but my reducer still won’t recognize this action.

Can you provide a basic demo? It would make this a lot easier :smile:

Also, any other error/warning in console?

It’s been a while since I last used redux, but seems like addUserInput is quite different from other action creators: it returns function while others just return an action.

@Marmiz When you click on pads, you will see that it’s logging out to the console. I am also console logging out in the reducer for that specific action.

@jenovs They are both valid. It’s usually objects that are retruned but I am also using Redux-Thunk which returns a function and call a dispatch function.

@Marmiz was right, you either need to bind action creators or mapDispatchToProps.

This works for me:

  render() {
    const { addUserInput } = this.props;

    return (
      <React.Fragment>
        <div className="pad1" ref={this.pad1} onClick={() => addUserInput(2)} />
        <div className="pad2" ref={this.pad2} onClick={() => addUserInput(2)} />
        <div className="pad3" ref={this.pad3} onClick={() => addUserInput(3)} />
        <div className="pad4" ref={this.pad4} onClick={() => addUserInput(4)} />
        {this.playGame()}
      </React.Fragment>
    );
  }
}

const mapStateToProps = state => {
  return {
    gameReducer: state.gameReducer,
  };
};

const mapDispatchToProps = dispatch => {
  return {
    addUserInput: input => {
      dispatch(addUserInput(input));
    },
    addNewSequence: () => dispatch(addNewSequence()),
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Pads);
1 Like

So I think the direction you gave me is just another way of dispatching actions and I confirmed it still does the same thing. It calls my action but my reducer still won’t recognize this action.

They are not the same things :slight_smile:

connect is an HOC, this means it takes a function and return a new function with something “enhanced”. In this case takes a class/function and return that with some extra data and the dispatch method as props.

What you have created is a curry function.
To give you an explanation:

Imagine that our dispatch is the following log function:

const log = (...arg) => console.log('dispatched ', ...arg);

Nothing fancy, but you can paste it in the console and test it out.

This is how you declared your “dispatch” factory function: a function that takes an argument, and return a function.

// remember log is our dispatch
const f = input => {
 console.log('action ', input);
 return (log) => {
   log(input)
  }
}

so if you invoke:

f(1) 
// action 1
// return [function]

and as you see there’s nothing that called our log function since f is returning a function.

In order to make it work you need to pass the desired function to the returned value of f
on in practice:

const myCustomEvent = f(1) // you'll see 'action 1' in console

myCustomEvent(log) // now we pass our missing piece, the second function
// dispatched 1

[yay! that worked finally]

However the advantage of using a function that pass log (or dispatch) as argument to connect is that you don’t need to declare the firs portion of the function yourself since the HOC is taking care of that.

Or in code:

// we are passing log as first argument
const fakeConnect = (log) => ({
  myCustomAction: x => log(x)
})

// then you connect a component
const connectedComponent = fakeConnect(log);

// in fact you have the Redux method as props 
// that's why you can this.props.myCustomAction

connectedComponent.myCustomAction("I'M ALIVE") // "dispatched I'M ALIVE"

This is a working model so you’re free to test it out in a REPL :slight_smile:

…phew, that took a while.

Also personal side-note / suggestion: don’t assume you’re right and everyone else is wrong
we’re here trying to help and not trying to make your life miserable :wink:

3 Likes

Thank you guys for helping me out a ton! I know how time consuming it is to trying to debug other people’s codes so I really appreciate your time + efforts.

@Marmiz That was lengthy but very well explained I am getting hang of it :slight_smile:
Also sorry if I sounded like a jerk saying only I was right and you guys were wrong :sob: that wasn’t my intention.

So here is what was wrong. I simply didn’t declare my function inside render method. so after bringing it in, it worked. (Pretty dumb mistake)
const { addUserInput } = this.props;

I was confused initially because there are two ways of dispatching actions the way I was using actions was through mapdispatchtoprops-as-an-object but you introduced me mapdispatchtoprops-as-a-function which explicitly calls dispatch method.

Thanks for this @shimphillip , I had a hard time finding this bug because it doesn’t raise any errors. Weird.