javascript 注销时,Redux不会返回到初始状态

pbgvytdp  于 2023-04-04  发布在  Java
关注(0)|答案(2)|浏览(80)

在我的redux调度了logout操作之后,我想重置到我的初始状态。我正在使用nextjs,我不明白为什么我想要的注销reducer在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函数组件,我想从slice中调度logout操作,或者调度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;
kyvafyod

kyvafyod1#

你正在使用redux persistent,所以你必须以不同的方式注销。

import { persistor } from './store'

const handleLogout = () => {
  dispatch({ type: 'LOGOUT' })
  persistor.purge()
}
lsmepo6l

lsmepo6l2#

问题

logout是一个函数,而不是一个动作对象,所以额外的reducer case没有运行。

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

...

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

溶液

解决方案是通过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 reducer 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;

相关问题