在我的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函数组件,我想在其中分派切片中的logout操作或分派注销函数以返回到我的初始状态.

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;

推荐答案

Issue

logout是一个函数,而不是一个动作对象,所以额外的减速器用例没有运行.

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

...

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

Solution

解决方案是通过createAction实用程序将logout声明为已创建的操作.

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减速器 case ,这将生成可以导出的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相关问答推荐

Klaro与Angular的集成

没有输出到带有chrome.Devtools扩展的控制台

使用i18next在React中不重新加载翻译动态数据的问题

D3 Scale在v6中工作,但在v7中不工作

如何在Obsidian dataview中创建进度条

切换时排序对象数组,切换不起作用

我的服务工作器没有连接到我的Chrome扩展中的内容脚本.我该怎么解决这个问题?

在Three JS中看不到补间不透明度更改效果

虚拟滚动实现使向下滚动可滚动到末尾

是否可以在Photoshop CC中zoom 路径项?

为什么我的按钮没有从&q;1更改为&q;X&q;?

如何限制显示在分页中的可见页面的数量

自定义图表工具提示以仅显示Y值

FileReader()不能处理Firefox和GiB文件

在查看网页时,如何使HTML中的按钮工作方式类似于鼠标上的滚轮或箭头键?

自动滚动功能在当前图像左侧显示上一张图像的一部分

在JavaScript中将Base64转换为JSON

bootstrap S JS赢得了REACT中的函数/加载

正则表达式以确定给定文本是否不只包含邮箱字符串

Firefox的绝对定位没有达到预期效果