4
votes

I am trying to implement auth (sign up/out) using React + Redux (SSR and Thunks). I have no idea why components are not updatating when Redux state updates...

This is the component that should get rerendered:

class Navbar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loggedIn: props.authentication.loggedIn
    };
  }

  render() {
    let links = null;
    if (this.state.loggedIn) {
      links = ...
    } else {
      links = ...
    }

    return (<Toolbar>{links}</Toolbar>)
  }
}

const mapStateToProps = state => {
  return {
    authentication: state.authentication
  }
}

const mapDispatchToProps = dispatch => {
  return {
    signOut: () => {dispatch(userActions.logout())}
  }
}

const AuthNavbar = connect(mapStateToProps, mapDispatchToProps)(Navbar)
export default AuthNavbar;

And that is my reducer:

const reducers = {
  authentication,
  registration,
  alert
}

const todoApp = combineReducers(reducers)
export default todoApp

Authentication reducer:

const authentication = (state = initialState, action) => {
  switch (action.type) {
    ...
    case userConstants.LOGIN_SUCCESS:
      return Object.assign({}, state, {
        loggedIn: true,
        loggingIn: false,
        user: action.user
      });
    ...
    default:
      return state;
  }
}

And The Action - Login:

function login(email, password) {
  return dispatch => {
    dispatch({type: userConstants.LOGIN_REQUEST, email});
    userService.login(email, password).then(
        user => {
          dispatch({type: userConstants.LOGIN_SUCCESS, user});
        },
        error => {
          dispatch({ type: userConstants.LOGIN_FAILURE });
          dispatch({type: alertActions.error(error)});
        }
   );
  }
}

UserService.login is a function that calls and api witch fetch. Looks like Action gets fired as it should, Redux state gets updated, but the component does not update: enter image description here Double checked Redux Dev Tools - state does get updated, so there must be a problem with the way I am using connect utilities?

2

2 Answers

4
votes

You are storing the logedin props in the state inside the constructor, which will run only once in the life time of the component.
When a new prop is coming back you are not updating the state.

Either use the props directly:

if (this.props.authentication.loggedIn) {
      links = ...  

Or update the state in componentWillReceiveProps

componentWillReceiveProps(nextProps){
  // update the state with the new props
  this.setState({
      loggedIn: nextProps.authentication.loggedIn
  });
}
2
votes

Your render function is dependent on state.loggedIn, but state.loggedIn is not changing; only this.props.authentication.loggedIn is changing in response to the action. Your component, in its current form, does not need state. You can remove it to make this work:

class Navbar extends React.Component {
  render() {
    let links = null;
    if (this.props.authentication.loggedIn) {
      links = ...
    } else {
      links = ...
    }

    return (<Toolbar>{links}</Toolbar>)
  }
}