When Redux state changes all components get updated values EXCEPT one

Hello campers!
In my component A, I want to get the isAuthenticated prop from Redux state. It’s always null, which is the initial value, whereas in all other components it’s always the latest value.
So, when user authenticates I send their credentials to the server. If it’s a success I store the token in Redux state. But my component A doesn’t see that token.
I tried to connect the Redux store directly to the component A and extract that isAuthenticated, but again it’s always null.

Component A:

import React from "react";

import { connect } from "react-redux";

import { auth } from "../../store/actions/index";

import { Redirect } from "react-router-dom";

import Input from "../../components/UI/input/input";

import Button from "../../components/UI/button/button";

class Auth extends React.Component {

  state = {

    controls: {

      email: {

        elType: "input",

        elConfig: {

          type: "email",

          name: "email",

          placeholder: "Email",

          label: "Email"

        },

        value: "",

        validation: {

          required: true,

          isEmail: true

        },

        valid: false,

        touched: false

      },

      password: {

        elType: "input",

        elConfig: {

          type: "password",

          name: "password",

          label: "Password",

          placeholder: "Password"

        },

        value: "",

        validation: {

          required: true,

          minLength: 9

        },

        valid: false,

        touched: false,

        redirect: null

      }

    }

  };

  checkValidity = (value, rules) => {

    let valid = true;

    if (!rules) return true;

    if (rules.required) valid = value.trim() !== "" && valid;

    if (rules.minLength) valid = value.length >= rules.minLength && valid;

    if (rules.maxLength) valid = value.length <= rules.maxLength && valid;

    if (rules.isEmail) {

      const pattern = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/;

      valid = pattern.test(value) && valid;

    }

    return valid;

  };

  inputChangedHandler = (e, elId) => {

    const updatedControls = {

      ...this.state.controls,

      [elId]: {

        ...this.state.controls[elId],

        value: e.target.value,

        valid: this.checkValidity(

          e.target.value,

          this.state.controls[elId].validation

        ),

        touched: true

      }

    };

    this.setState({

      controls: updatedControls

    });

  };

  signUpRedirect = () => {

    this.setState({

      redirect: "/sign-up"

    });

  };

  signInRedirect = () => {

    this.setState({

      redirect: "/sign-in"

    });

  };

  submitHandler = e => {

    e.preventDefault();

    this.props.onAuth(

      this.state.controls.email.value,

      this.state.controls.password.value,

      this.props.signUp

    );

  };

  render() {

    console.log(this.props.isAuthenticated);

    console.log(this.props);

    const formElementsArray = [];

    const { controls } = this.state;

    for (let key in controls) {

      formElementsArray.push({

        id: key,

        config: controls[key]

      });

    }

    const form = formElementsArray.map(el => (

      <Input

        key={el.id}

        elType={el.config.elType}

        elConfig={el.config.elConfig}

        value={el.config.value}

        shouldValidate={el.config.validation}

        touched={el.config.touched}

        valid={el.config.valid}

        name={el.config.elConfig.name}

        label={el.config.elConfig.label}

        placeholder={el.config.elConfig.placeholder}

        changed={e => this.inputChangedHandler(e, el.id)}

      />

    ));

    return (

      <section className="section-auth">

        {this.state.redirect !== null && this.state.redirect !== undefined && (

          <Redirect to={this.state.redirect} />

        )}

        <form onSubmit={this.submitHandler} className="section-auth__form">

          <h2 className="section-auth__title">

            {this.props.signUp ? "Sign up" : "Sign in"}

          </h2>

          {form}

          <Button

            type="submit"

            className="button--secondary"

            style={{

              marginTop: "2rem"

            }}

          >

            SUBMIT

          </Button>

          {this.props.signUp ? (

            <div className="section-auth__btn-box">

              <p className="section-auth__text">Already have an account?</p>

              <Button

                clicked={this.signInRedirect}

                type="button"

                className="button--primary section-auth__btn"

              >

                Sign in

              </Button>

            </div>

          ) : (

            <div className="section-auth__btn-box">

              <p className="section-auth__text">Don't have an account?</p>

              <Button

                clicked={this.signUpRedirect}

                type="button"

                className="button--primary section-auth__btn"

              >

                Sign up

              </Button>

            </div>

          )}

        </form>

      </section>

    );

  }

}

const mapStateToProps = state => ({

  isAuthenticated: state.auth.token

});

const mapDispatchToProps = dispatch => ({

  onAuth: (email, password, signUp) => dispatch(auth(email, password, signUp))

});

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

Action creators:

// Firebase App (the core Firebase SDK) is always required and must be listed first

import * as firebase from "firebase";

import {

  AUTH_START,

  AUTH_SUCCESS,

  AUTH_FAIL,

  AUTH_SIGNOUT

} from "./actionTypes";

const tokenExpTimeInMs = 3600000;

const saveToLocalStorage = (token, expDate, userId) => {

  localStorage.setItem("token", token);

  localStorage.setItem("expirationDate", expDate);

  localStorage.setItem("userId", userId);

};

export const authStart = () => ({ type: AUTH_START });

export const authSuccess = (token, userId) => ({

  type: AUTH_SUCCESS,

  idToken: token,

  userId: userId

});

export const authFail = error => ({ type: AUTH_FAIL, error: error });

export const authSignout = () => {

  localStorage.removeItem("token");

  localStorage.removeItem("expirationDate");

  localStorage.removeItem("userId");

  return {

    type: AUTH_SIGNOUT

  };

};

export const checkAuthTimeout = expTime => dispatch => {

  setTimeout(() => {

    dispatch(authSignout());

  }, expTime);

};

export const auth = (email, password, signUp) => dispatch => {

  dispatch(authStart());

  if (signUp) {

    firebase

      .auth()

      .createUserWithEmailAndPassword(email, password)

      .then(response => {

        response.user.getIdToken().then(token => {

          const expirationDate = new Date(

            new Date().getTime() + tokenExpTimeInMs

          );

          saveToLocalStorage(token, expirationDate, response.user.uid);

          dispatch(checkAuthTimeout(tokenExpTimeInMs));

          dispatch(authSuccess(token, response.user.uid));

        });

      })

      .catch(error => {

        console.log(error);

        dispatch(authFail(error));

      });

  } else {

    firebase

      .auth()

      .signInWithEmailAndPassword(email, password)

      .then(response => {

        response.user.getIdToken().then(token => {

          const expirationDate = new Date(

            new Date().getTime() + tokenExpTimeInMs

          );

          saveToLocalStorage(token, expirationDate, response.user.uid);

          dispatch(checkAuthTimeout(tokenExpTimeInMs));

          dispatch(authSuccess(token, response.user.uid));

        });

      })

      .catch(error => {

        console.log(error);

        dispatch(authFail(error));

      });

  }

};

export const authCheckState = () => dispatch => {

  const token = localStorage.getItem("token");

  if (!token) {

    dispatch(authSignout());

  } else {

    const expDate = new Date(localStorage.getItem("expirationDate"));

    if (expDate <= new Date()) {

      dispatch(authSignout());

    } else {

      const userId = localStorage.getItem("userId");

      dispatch(authSuccess(token, userId));

      dispatch(checkAuthTimeout(expDate.getTime() - new Date().getTime()));

    }

  }

};

Reducer:

import {

  AUTH_START,

  AUTH_SUCCESS,

  AUTH_FAIL,

  AUTH_SIGNOUT

} from "../actions/actionTypes";

const updateObject = (oldObject, updatedProperties) => {
  return {
    ...oldObject,
    ...updatedProperties
  };
};


const initialState = {

  token: null,

  userId: null,

  error: null

};

const authStart = (state, action) => updateObject(state, { error: null });

const authSuccess = (state, action) => {

  return updateObject(state, {

    token: action.idToken,

    userId: action.userId,

    error: null

  });

};

const authFail = (state, action) =>

  updateObject(state, {

    error: action.error

  });

const authSignout = (state, action) =>

  updateObject(state, { token: null, userId: null });

export default (state = initialState, action) => {

  switch (action.type) {

    case AUTH_START:

      return authStart(state, action);

    case AUTH_SUCCESS:

      return authSuccess(state, action);

    case AUTH_FAIL:

      return authFail(state, action);

    case AUTH_SIGNOUT:

      return authSignout(state, action);

    default:

      return state;

  }

};

Redux store:

import thunk from "redux-thunk";

import { createStore, combineReducers, applyMiddleware, compose } from "redux";

import authReducer from "./reducers/auth";

import userCdtReducer from "./reducers/userCountdownTimers";

import eventFormReducer from "./reducers/eventForm";

const rootReducer = combineReducers({

  auth: authReducer,

  userCdt: userCdtReducer,

  eventData: eventFormReducer

});

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default createStore(

  rootReducer,

  composeEnhancers(applyMiddleware(thunk))

);

If you need the full code here is the GitHub repo

I will appreciate any help!
Thank you!

It looks like you got it fixed? I checked here and couldn’t find the problem.