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.info("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;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
0
93
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы используете избыточное сохранение, поэтому вам нужно выйти из системы по-другому.

import { persistor } from './store'

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

это сработало!. но мне нужно обновить его, прежде чем он изменит мой заголовок обратно на «Войти и зарегистрироваться». Можете ли вы помочь мне избежать обновления страницы? Вот что я сделал const handleLogoutClick = (e) => { e.preventDefault(); console.info("Выход из системы"); диспетчеризация (выход пользователя ()); персистент.purge(); роутер.push("/"); };

Jc John 03.04.2023 06:01

Я думаю, что purge очищает все сохраненные данные, не так ли?

Yilmaz 03.04.2023 06:03

Да, purge только «удаляет состояние с диска и возвращает промис», он ничего не делает с текущим значением хранилища Redux в памяти. Этот код не исправит фактический сброс среза состояния, как того хочет OP. Он работает только путем удаления сохраненного значения, и когда страница перезагружается, нет ничего, что могло бы повторно гидратировать состояние, поэтому используется начальное значение.

Drew Reese 03.04.2023 07:24
Ответ принят как подходящий

Проблема

logout — это функция, а не объект действия, поэтому дополнительный редьюсер не работает.

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

...

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

Решение

Решением будет объявить logout как созданное действие с помощью утилиты createAction.

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, который будет генерировать действие 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;

Другие вопросы по теме