João Lima
João Lima

Reputation: 430

Updating Redux state does not trigger componentWillReceiveProps

I'm trying to validate the login information. After making sure the login is valid I want to fire a new route. I pass the state.loginReducer.login as props. When I handle the submit event, an action is dispatched, changing the global login state.

Shouldn't ComponentWillReceiveProps be fired in this case? since the props changed?. Is there a better way to implement this functionality?

handleSubmit (evt) {
    const {
        dispatch,
        login
    } = this.props;

    dispatch(actions.doLogin(value.login));
}

ComponentWillReceiveProps (nextprops) {
    const {
        login
    } = this.nextProps;

    if (login != null) {
        history.pushState({}, '/account');
    }
}

function mapStateToProps (state) {
    return {
        login: state.loginReducer.login
    }
}

export default connect(mapStateToProps)(Login);

Upvotes: 25

Views: 26711

Answers (3)

vcycyv
vcycyv

Reputation: 620

ComponentWillReceiveProps (nextprops)

should be

componentWillReceiveProps (nextprops)

The C should be lower case. Actually, mapStateToProps triggers componentWillReceiveProps. I'm sure about that.

Upvotes: 12

Alone Bashan
Alone Bashan

Reputation: 116

Do the following:

function mapStateToProps (state) {
    return {
        login: Object.assign({}, state.loginReducer.login),
    }
}

For making sure the object return is actually new.

Upvotes: 3

Nathan Hagen
Nathan Hagen

Reputation: 12780

If state.loginReducer.login changes, then componentWillReceiveProps will get triggered. If you believe your reducer is returning a new state, and componentWillReceiveProps is not being triggered, make sure that the new state is immutable. Returning the same state reference thats passed to the reducer won't work.

From https://github.com/reactjs/redux/blob/master/docs/Troubleshooting.md

This is wrong:

function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    // Wrong! This mutates state
    state.push({
      text: action.text,
      completed: false
    });
  case 'COMPLETE_TODO':
    // Wrong! This mutates state[action.index].
    state[action.index].completed = true;
  }

  return state;
}

This is right:

function todos(state = [], action) {
  switch (action.type) {
  case 'ADD_TODO':
    // Return a new array
    return [...state, {
      text: action.text,
      completed: false
    }];
  case 'COMPLETE_TODO':
    // Return a new array
    return [
      ...state.slice(0, action.index),
      // Copy the object before mutating
      Object.assign({}, state[action.index], {
        completed: true
      }),
      ...state.slice(action.index + 1)
    ];
  default:
    return state;
  }
}

Upvotes: 33

Related Questions