35

I am currently following this tutorial. I've hit a bit of a snag involving mapStateToProps in the following code:

import React from 'react';
import Voting from './voting';
import {connect} from 'react-redux';

const mapStateToProps = (state) => {
  return {
    pair: state.getIn(['vote','pair']),
    winner: state.get('winner')
  };
}

const VotingContainer = connect(mapStateToProps)(Voting);
export default VotingContainer;

Here is the Voting component that's imported:

import React from 'react';
import Vote from './Vote';
import Winner from './winner';

const Voting = ({pair,vote,hasVoted,winner}) =>
  <div>
    {winner ? <Winner winner={winner}/>  :
      <Vote pair={pair} vote={vote} hasVoted={hasVoted}/>
    }
  </div>

export default Voting;

It is supposed to render two buttons from the pair prop. The vote prop is a function that will be executed on click, hasVoted disables buttons when true and winner only renders the winner component as shown.

The state is expected to be an immutableJS map that looks like this:

Map({
  vote:{
    pair:List.of('Movie A','Movie B')
  }
});

Instead I am getting an error saying that state is undefined in the state.getIn line.

The code setting the state is in index:

const store = createStore(reducer);

const socket = io(document.location.protocol + '//' + document.location.hostname + ':8090');
socket.on('state', state => store.dispatch({
  type: 'SET_STATE',
  state
}));

I have logged store.getState()after setting and it is as expected but undefined in mapStateToProps. I also logged the state variable in above context and it's also as expected.

I also set the state normally and it surprisingly works!:

store.dispatch({
  type: 'SET_STATE',
  state: {
    vote: {
      pair: ['Movie A', 'Movie B']
    }
  }
});

The value of state above is exactly what is received from the server

Lastly here's what my reducer looks like:

import React from 'react';
import {Map, fromJS} from 'immutable';

const reducer = (state = Map(), action) => {
  switch (action.type) {
    case 'SET_STATE':
      return state.merge(action.state);
  }
}

export default reducer;

What am I doing wrong?

EDIT: I realised that mapStateToProps is not being called after the store.dispatch(). I went through the docs for the possible reasons mapStateToProps is not being called and it's not one of them.

esaminu
  • 402
  • 1
  • 4
  • 9
  • i suggest you add `redux-logger` to existing middlewares to verify if the actions are properly dispatched or not; it could give us a better idea – Deadfish Aug 18 '16 at 09:57
  • @Deadfish Thanks for the suggestion. I used redux-logger and the action is being dispatched correctly although I don't know why the previous state is undefined since my initial state is an empty Map. I also realised that for the one involving the server, mapStateToProps is not called after the dispatch. – esaminu Aug 18 '16 at 15:41
  • i think the `mapStateToProps` is not called when the state is mutated; but your reducer code looks fine; could you share your whole code through github or gist; something must have been wrong with the way it was setup – Deadfish Aug 18 '16 at 16:11
  • @Deadfish Sure, [server](https://github.com/esaminu/redux-voting-server) and the [client](https://github.com/esaminu/redux-voting-client) – esaminu Aug 18 '16 at 16:41

2 Answers2

74

You reducer doesn't have a default action in switch statement. Which is why even though you mentioned the initial state in reducer params, undefined is returned as store initial state

import React from 'react';
import {Map,fromJS} from 'immutable';

const reducer = (state = Map() ,action) => {
  switch(action.type){
    case 'SET_STATE': return state.merge(action.state);
    default:
      return state;
  }
}

export default reducer;

Adding the default statement will fix the issue :)

Deadfish
  • 2,047
  • 16
  • 17
  • 1
    thanks so much @Deadfish! I literally redid [this](https://www.youtube.com/watch?v=9boMnm5X9ak&list=PLC3y8-rFHvwheJHvseC3I0HuYI2f46oAK&index=2) entire playlist just because of this error. Thanks again! – theProCoder Nov 17 '21 at 11:58
2

I ended up here too because I had failed to pass my rootreducer function to my createStore method. I had:

const store = createStore(applyMiddleware(...middlewares));

I needed:

const store = createStore(rootReducer(), applyMiddleware(...middlewares));
duhaime
  • 25,611
  • 17
  • 169
  • 224