javascript - 注销时 Redux 不会返回到我的初始状态

标签 javascript reactjs react-redux dispatch next.js13

在我的 redux 调度 logout 操作后,我想重置为初始状态。我正在使用 nextjs,但我不明白为什么 authenticateSlice.js 中我想要的注销缩减程序没有执行。我还使用了 redux-persist 来保持我的状态持久。

这是我来自 store.js 的代码

import { configureStore } from "@reduxjs/toolkit";
import authenticateSlice from "./slices/authenticateSlice";
import { persistReducer, persistStore } from "redux-persist"; // import persistStore
import storage from "./storage";
import { encryptTransform } from "redux-persist-transform-encrypt";
import { combineReducers } from "redux";
import thunk from "redux-thunk";

const reducers = combineReducers({
  auth: authenticateSlice.reducer,
});

let transforms = null;

if (process.env.NODE_ENV === "production") {
  const encrypt = encryptTransform({
    secretKey: process.env.NEXT_PUBLIC_REDUX_SECRET,
    onError: function (error) {
      // Handle the error.
    },
  });
  transforms = [encrypt];
}

const persistConfig = {
  key: "root",
  storage: storage,
  transforms,
};

const persistedReducer = persistReducer(persistConfig, reducers);

const store = configureStore({
  reducer: persistedReducer,
  middleware: [thunk],
});

let persistor = persistStore(store); // initialize persistor

export { store, persistor };

这是我来自 authenticateSlice.js 的代码,我有 logout 函数来调度。

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { commonPostRequest } from "@/django-api/common/commonRequestAPI";
import { CommonPostHeader } from "@/django-api/common/commonHeadersAPI";

export const fetchUserLogin = createAsyncThunk(
  "auth/login",
  async (arg, { rejectWithValue }) => {
    const { username, password } = arg;
    try {
      const loginRequest = await commonPostRequest({
        body: { username: username, password: password },
        headers: CommonPostHeader,
        url: "http://localhost:8000/api/accounts_app/login",
      });
      if (loginRequest.data) {
        return loginRequest.data;
      } else {
        throw new Error(loginRequest.message);
      }
    } catch (err) {
      return rejectWithValue(err.message);
    }
  }
);

export const logout = () => {
  return { type: "auth/logout" };
};

// loading: 'idle' | 'pending' | 'succeeded' | 'failed'
const initialState = {
  data: {},
  loading: "idle",
  message: "",
};

const authenticateSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserLogin.pending, (state) => {
        state.loading = "pending";
      })
      .addCase(fetchUserLogin.fulfilled, (state, action) => {
        state.loading = "succeeded";
        state.data = action.payload;
      })
      .addCase(fetchUserLogin.rejected, (state, action) => {
        state.loading = "failed";
        state.message = action.payload;
      })
      .addCase(logout, (state) => {
        Object.assign(state, initialState);
      });
  },
});

export default authenticateSlice;

最后,这是我的 Header 函数组件,我想在其中分派(dispatch)切片中的 logout 操作或分派(dispatch)注销函数以返回初始状态。

import { Typography } from "@mui/material";
import { Row, Col, Divider, notification } from "antd";
import styles from "./Header.module.scss";
import Image from "next/image";
import Link from "next/link";
import {
  toLocalZoneDateTime,
  getCurrentDateTimeStamp,
} from "../common/functions/datetime";
import { useDispatch } from "react-redux";
import { useRouter } from "next/router";
import { logout } from "../../next-redux/slices/authenticateSlice";

const Header = (props) => {
  const dispatch = useDispatch();
  const { user } = props;
  const router = useRouter();

  const currentDateTimeStamp = getCurrentDateTimeStamp();

  const handleLogoutClick = (e) => {
    e.preventDefault();
    console.log("logout");
    dispatch(logout());
  };

  return (
    <>
      <Row>
        <Col span={24}>
          <Row gutter={[8, 8]} className={styles.topBar}>
            <Col span={12}>
              <Typography variant="subtitle2" className={styles.topDate}>
                {toLocalZoneDateTime(currentDateTimeStamp)}
              </Typography>
            </Col>
            <Col span={12}>
              {user ? (
                <Typography align="right">
                  <a
                    onClick={(e) => {
                      handleLogoutClick(e);
                    }}
                    className={styles.topBarLinks}
                  >
                    Logout
                  </a>
                </Typography>
              ) : (
                <>
                  <Typography align="right">
                    {" "}
                    <Link href="/signin/" className={styles.topBarLinks}>
                      Sign-in
                    </Link>{" "}
                    <Link href="/signup/" className={styles.topBarLinks}>
                      Sign-up
                    </Link>
                  </Typography>
                </>
              )}
            </Col>
          </Row>
        </Col>
      </Row>
    </>
  );
};

export default Header;

最佳答案

问题

logout 是一个函数,而不是一个操作对象,因此额外的 reducer 案例没有运行。

export const logout = () => {
  return { type: "auth/logout" };
};

...

.addCase(logout, (state) => { // <-- function, e.g. logout.type undefined
  Object.assign(state, initialState);
});

解决方案

解决方案是通过 createActionlogout 声明为创建的操作实用程序。

import { createSlice, createAction, createAsyncThunk } from "@reduxjs/toolkit";
import { commonPostRequest } from "@/django-api/common/commonRequestAPI";
import { CommonPostHeader } from "@/django-api/common/commonHeadersAPI";

export const fetchUserLogin = createAsyncThunk(
  ...
);

export const logout = createAction("auth/logout");

const initialState = { ... };

const authenticateSlice = createSlice({
  name: "auth",
  initialState,
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserLogin.pending, (state) => {
        state.loading = "pending";
      })
      .addCase(fetchUserLogin.fulfilled, (state, action) => {
        state.loading = "succeeded";
        state.data = action.payload;
      })
      .addCase(fetchUserLogin.rejected, (state, action) => {
        state.loading = "failed";
        state.message = action.payload;
      })
      .addCase(logout, (state) => {
        return initialState;
      });
  },
});

export default authenticateSlice.reducer;

或者声明一个logout reducer 案例,它将生成可以导出的logout操作。

import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { commonPostRequest } from "@/django-api/common/commonRequestAPI";
import { CommonPostHeader } from "@/django-api/common/commonHeadersAPI";

export const fetchUserLogin = createAsyncThunk(
  ...
);

const initialState = { ... };

const authenticateSlice = createSlice({
  name: "auth",
  initialState,
  reducers: {
    logout: (state) => {
      return initialState;
    },
  },
  extraReducers: (builder) => {
    builder
      .addCase(fetchUserLogin.pending, (state) => {
        state.loading = "pending";
      })
      .addCase(fetchUserLogin.fulfilled, (state, action) => {
        state.loading = "succeeded";
        state.data = action.payload;
      })
      .addCase(fetchUserLogin.rejected, (state, action) => {
        state.loading = "failed";
        state.message = action.payload;
      });
  },
});

export const { logout } = authenticateSlice.actions;

export default authenticateSlice.reducer;

关于javascript - 注销时 Redux 不会返回到我的初始状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75915762/

相关文章:

reactjs - react-native run-android 和 expo start 之间有什么区别?

javascript - 警告 : Unknown DOM property class. 你是说类名吗?

javascript - 使用CDN时如何调用react logger函数

javascript - 在控制流之外调用的函数?

javascript - Angular 变量未绑定(bind)到 View

javascript - 未调用 Checkbox 的 onChange 函数

javascript - 未找到 React Redux Store 变量,即使它在存储中

javascript - 调用 API 时 redux 函数 mapDispatchToProps 错误

java - 如何在 JavaScript 中调用 servlet?

javascript - 为什么jQuery或诸如getElementById之类的DOM方法找不到元素?