store/index.js
import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "../reducers/index";
const store = configureStore({
reducer: {
user: rootReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
export default store;
userSlice.js
import { createSlice } from "@reduxjs/toolkit";
export const INITIAL_STATE = {
name: "Hello World",
email: "",
photo: "",
};
export const userSlice = createSlice({
name: "user",
initialState: INITIAL_STATE,
reducers: {
setUserLoginDetails: (state, action) => {
console.log("Initial", state.name);
state.name = action.payload.name;
state.email = action.payload.email;
state.photo = action.payload.photo;
console.log("Updated", state.name);
},
setSignOutState: (state) => {
state.name = null;
state.email = null;
state.photo = null;
},
},
});
export const { setUserLoginDetails, setSignOutState } = userSlice.actions;
export const selectUserName = (state) => state.user.name;
export const selectUserEmail = (state) => state.user.email;
export const selectUserPhoto = (state) => state.user.photo;
export default userSlice.reducer;
AuthContext.js
import React, { useContext, createContext, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
GoogleAuthProvider,
signInWithPopup,
signInWithRedirect,
signOut,
onAuthStateChanged,
} from "firebase/auth";
import { auth } from "../firebase";
import { setUserLoginDetails, selectUserName } from "../reducers/userSlice";
import store from "../store/index";
const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
const dispatch = useDispatch();
const username = useSelector(selectUserName);
const googleSignIn = () => {
const provider = new GoogleAuthProvider();
signInWithPopup(auth, provider)
.then((result) => {
console.log("Check Initial Store", store.getState());
console.log("Check Initial Name", username);
setUser(result.user);
console.log("Check Updated Store", store.getState());
console.log("Check Updated Name", username);
})
.catch((e) => {
const eCode = e.code;
const eMessage = e.message;
const eEmail = e.email;
const eCredential = e.credential;
});
};
const setUser = (user) => {
dispatch(
setUserLoginDetails({
name: user.displayName,
email: user.email,
photo: user.photoURL,
})
);
};
return (
<AuthContext.Provider value={{ googleSignIn, username }}>
{children}
</AuthContext.Provider>
);
};
export default AuthContext;
export const UserAuth = () => {
return useContext(AuthContext);
};
App.js
import {
BrowserRouter as Router,
Route,
Routes,
Navigate,
} from "react-router-dom";
import "./App.css";
import Header from "./components/Header";
import Home from "./components/Home";
import Login from "./components/Login";
import { AuthContextProvider, UserAuth } from "./context/AuthContext";
import { useEffect } from "react";
//import { useSelector } from "react-redux";
//import { selectUserName } from "./reducers/userSlice";
import { onAuthStateChanged } from "firebase/auth";
function App(props) {
const { username } = UserAuth();
useEffect(() => {
//if (username != null) {
console.log("User name is", username);
//}
}, );
return (
<div className="App">
<AuthContextProvider>
<Router>
<Routes>
<Route
exact
path="/"
element={/*username ? <Navigate to="/home" /> : */<Login />}
/>
<Route
path="/home"
element={
/*!username ? (
<Navigate to="/" />
) :*/ (
<>
<Header />
<Home />
</>
)
}
/>
{/*<Route path="/redirect" element={<Navigate to="/home" />} />*/}
</Routes>
</Router>
</AuthContextProvider>
</div>
);
}
export default App;
The problem lies in AuthContext.js
, where I am attempting to select the current user name via useSelector(SelectUserName)
from userSlice.js, which is (state) => state.user.name
. The console.log
outputted the log in the attached image:
Edit: I forgot to add my reducers/index.js
so here you go.
reducers/index.js
import { combineReducers } from "redux";
import userReducer from "./userSlice";
const rootReducer = combineReducers({
userState: userReducer,
});
export default rootReducer;
Thanks a lot everyone for the response. I’ve tried converting this under userSlice.js
:
from
selectUserName = (state) => state.user.name;
to
selectUserName = (state) => state.user.userState.name;
And I was able to get the username
proper, rather than unknown
. Any further suggestion will be greatly appreciated.
2
Answers
This part of your store setup may be the issue:
What exactly is
rootReducer
? This looks like you either want to do something like this instead:Or set the reducers for each slice like so:
https://redux-toolkit.js.org/tutorials/quick-start#add-slice-reducers-to-the-store
Based on the screenshot you’ve included in your post it is clear that the Redux store has the following structure:
In other words, to select the
name
state it is notstate.user.name
, but ratherstate.user.userState.name
.You can fix the selector functions to select the appropriate state using the correct path.
Example:
It might just be more likely the case that you inadvertently "nested" this
userSlice.reducer
when exporting/combining into therootReducer
. It looks like you merged/combined auserState
reducer when creating therootReducer
and then merged the root reducer asuser
when configuring the store.The root reducer and store configuration should look similar to the following based on your current selector functions:
../userSlice.js selectors
../reducers/index.js
store/index.js