@reduxjs/toolkit - UseSelector返回Undefined而不是Google Username

zz2j4svz  于 2023-04-12  发布在  Go
关注(0)|答案(2)|浏览(151)

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);
    //}
  }, [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;

问题出在AuthContext.js,我试图通过useSelector(SelectUserName)从userSlice.js中选择当前用户名,即(state) => state.user.nameconsole.log在附件中输出了日志:

编辑:我忘了添加我的reducers/index.js,所以在这里你去。
reducers/index.js

import { combineReducers } from "redux";
import userReducer from "./userSlice";

const rootReducer = combineReducers({
  userState: userReducer,
});

export default rootReducer;

非常感谢大家的回应。我已经尝试在userSlice.js下转换:
selectUserName = (state) => state.user.name;selectUserName = (state) => state.user.userState.name;
而且我能够得到正确的username,而不是unknown。任何进一步的建议将不胜感激。

np8igboo

np8igboo1#

根据您在帖子中包含的屏幕截图,很明显Redux商店具有以下结构:

{
  user: {
    userState: {
      email: "....",
      name: "....",
      photo: "....",
    },
  },
}

换句话说,要选择name状态,它不是***state.user.name,而是state.user.userState.name
您可以修复选择器函数,以便使用正确的路径选择适当的状态。
示例:

export const selectUserName = (state) => state.user.userState.name;
export const selectUserEmail = (state) => state.user.userState.email;
export const selectUserPhoto = (state) => state.user.userState.photo;

更有可能的情况是,在导出/合并到rootReducer时,您无意中“嵌套”了这个userSlice.reducer。看起来像是在创建rootReducer时合并/合并了一个userState reducer,然后在配置存储时将根reducer合并为user
根reducer和store配置应该看起来类似于以下基于您当前的选择器函数:
../userSlice.js选择器

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;

../reducers/index.js

import { combineReducers } from 'redux';
import userReducer from '../userSlice';

const rootReducer = combineReducers({
  user: userReducer,
});

export default rootReducer;

store/index.js

import { configureStore } from "@reduxjs/toolkit";
import rootReducer from "../reducers";

const store = configureStore({
  reducer: rootReducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: false,
    }),
});

export default store;
a9wyjsp7

a9wyjsp72#

您的商店设置的这一部分可能是问题所在:

reducer: {
    user: rootReducer,
  },

rootReducer到底是什么?看起来你要么想做这样的事情:

reducer: rootReducer,

或者像这样为每个切片设置缩减器:

reducer: {
    user: userReducer,
  },

https://redux-toolkit.js.org/tutorials/quick-start#add-slice-reducers-to-the-store

相关问题