How to use firebase authentication with Redux Toolkit using onAuthStateChanged?

I’m trying to implement Firebase Authentication via Redux Toolkit. But I think I’m missing something due to lack of knowledge.

My monitorAuthChange returns undefined.

I have two separate files – first list of firebase functions, second Redux Toolkit slice.

import {
  createUserWithEmailAndPassword,
  onAuthStateChanged,
} from "firebase/auth";
import { auth } from "./firebaseConfig";

export const createAccount = async (email, password) => {
  try {
    await createUserWithEmailAndPassword(auth, email, password);
  } catch (error) {
    console.log(error);
  }
};

export const monitorAuthChange = () => {
  onAuthStateChanged(auth, (user) => {
    if (user) {
      return true;
    } else {
      return false;
    }
  });
};
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit";
import { createAccount, monitorAuthChange } from "../../service/userServices";

export const createUser = createAsyncThunk(
  "users/createUser",
  async ({ username, password }) => {
    await createAccount(username, password);
  }
);

const initialState = { loginStatus: false };

const userSlice = createSlice({
  name: "users",
  initialState,
  reducers: {},
  extraReducers: {
    [createUser.fulfilled]: (state, action) => {
      const result = monitorAuthChange();
      state.loginStatus = result;
    },
    [createUser.rejected]: (state, action) => {
      state.loginStatus = false;
    },
  },
});

export const selectAllUsers = (state) => state.users;
export default userSlice.reducer;

Two things make me confused:

    1. Thunk works – it creates account and I see it in Firebase. Do I need to track result of request in a different way?
    1. If add console.log(user) inside monitorAuthChange it logs data depends if user was created or not. But still returns undefined.
      Would appreciate any hint or advice or article to read to understand my mistake. Thanks in advance.

Here is Solutions:

We have many solutions to this problem, But we recommend you to use the first solution because it is tested & true solution that will 100% work for you.

Solution 1

It seems you want to track user auth with onAuthStateChanged
You have plenty way to plug this callback to redux.

You cannot call monitorAuthChange inside the reducer as they must be pure.

Using global store

// users.slice.ts
const userSlice = createSlice({
  name: "users",
  initialState,
  reducers: {
    setLoginStatus: (state, action) {
      state.loginStatus = action.payload;
    }
  },
  extraReducers: {
    [createUser.fulfilled]: (state, action) => {
      state.loginStatus = true;
    },
    [createUser.rejected]: (state, action) => {
      state.loginStatus = false;
    },
  },
});

// trackUserAuth.ts
onAuthStateChanged(auth, (user) => {
    if (user) {
      store.dispatch(setLoginStatus(true))
    } else {
      store.dispatch(setLoginStatus(true))
    }
});

Using hooks

export const useAuth = () => {
  const dispatch = useDispatch();
  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      if (user) {
        dispatch(setLoginStatus(true))
      } else {
        dispatch(setLoginStatus(true))
      }
    });
    return unsubscribe;
  }, []);
}

Using thunks

export const checkAuthStatus = () => (dispatch) {
  const unsubscribe = Firebase.auth().onAuthStateChanged(user => {
    if (user) {
      dispatch(setLoginStatus(true))
    } else {
      dispatch(setLoginStatus(true))
    }
  });

  return unsubscribe;
}

Note: Use and implement solution 1 because this method fully tested our system.
Thank you 🙂

All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Reply