使用redux工具包的本地存储

xriantvc  于 2022-11-12  发布在  其他
关注(0)|答案(3)|浏览(244)

我希望将isAuthenticated状态保存在本地存储中,这样在刷新页面后,用户就可以登录了。我尝试了简单的方法,在localStorage中将其设置为true/false,并在redux中将我的状态的初始值设置为该值,但它总是将其设置为true。
这是我的Redux商店

import { createSlice, configureStore } from '@reduxjs/toolkit';

//MOVEMENTS (doesn't work yet)
const initialMovementsState = {
  movements: [],
};

const movementsSlice = createSlice({
  name: 'movements',
  initialState: initialMovementsState,
  reducers: {
    add(state) {
      //nothing yet
    },
    decrement(state) {
      //nothing yet
    },
  },
});

//LOGGING IN/OUT
const initialAuthState = {
  isAuthenticated: false,
};

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    },
  },
});

//STORE CONFIGURATION

const store = configureStore({
  reducer: {
    movements: movementsSlice.reducer,
    auth: authSlice.reducer,
  },
});

export const movementsActions = movementsSlice.actions;
export const authActions = authSlice.actions;

export default store;

我找到的所有答案都是用redux的,而不是用redux工具包,我对redux有点陌生,所以我迷路了。

busg9geu

busg9geu1#

2022年10月更新:在1.8及更高版本中,您也可以使用redux-toolkit的createListenerMiddleware,即explained in this answer

修改localStorage是一个副作用,所以你不想在你的reducer中做这个。reducer应该总是没有副作用的。处理这个问题的一个方法是使用自定义中间件。

编写中间件

我们的中间件在每个动作被分派后被调用。如果动作是loginlogout,那么我们将改变localStorage的值。否则我们什么都不做。无论哪种方式,我们都将动作传递给链中的下一个中间件,return next(action)
redux-toolkit和vanilla redux中间件的唯一区别是我们如何检测loginlogout操作。对于redux-toolkit,操作创建器函数包括一个有用的match()函数,我们可以使用它,而不必查看type。我们知道,如果login.match(action)为真,则action是一个登录操作。因此,我们的中间件可能如下所示:

const authMiddleware = (store) => (next) => (action) => {
  if (authActions.login.match(action)) {
    // Note: localStorage expects a string
    localStorage.setItem('isAuthenticated', 'true');
  } else if (authActions.logout.match(action)) {
    localStorage.setItem('isAuthenticated', 'false');
  }
  return next(action);
};

应用中间件

您将在configureStore函数中将中间件添加到您的存储中。Redux-toolkit includes some middleware by default with启用了thunk、不变性检查和可序列化检查。现在您根本没有在存储中设置middleware属性,因此您将获得包括在内的所有默认值。我们希望确保在添加自定义中间件时保留默认值。
middleware属性可以被定义为一个函数,它被redux-toolkit的getDefaultMiddleware函数调用。这允许你为默认的中间件设置选项,如果你愿意的话,同时也可以添加我们自己的选项。我们将按照docs的例子写如下:

const store = configureStore({
  reducer: {
    movements: movementsSlice.reducer,
    auth: authSlice.reducer,
  },
  // Note: you can include options in the argument of the getDefaultMiddleware function call.
  middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(authMiddleware)
});

不要执行此操作,因为这将删除所有默认中间件

const store = configureStore({
  reducer: {
    movements: movementsSlice.reducer,
    auth: authSlice.reducer,
  },
  middleware: [authMiddleware]
});

通过中间件同步状态

我们可以通过匹配 allauth操作来简化中间件,我们在action.type上使用String.prototype.startsWith()方法(类似于addMatcher文档部分中的例子,使用.endswith())。
这里,我们通过在修改localStorage * 之前 * 执行next(action)来找到下一个状态。我们将localStorage的值设置为auth切片返回的新状态。

const authMiddleware = (store) => (next) => (action) => {
  const result = next(action);
  if ( action.type?.startsWith('auth/') ) {
    const authState = store.getState().auth;
    localStorage.setItem('auth', JSON.stringify(authState))
  }
  return result;
};

或者,您可以使用redux-persist包,它可以为您完成此任务。

6jygbczu

6jygbczu2#

与此同时,我已经编写了移动的逻辑,并希望将所有状态保存在本地存储中。琳达Paiste的回答非常有帮助(如此长而直接的回答值得称赞!),但我在将本地存储发送回redux状态时遇到了困难。以下是工作解决方案:

import { createSlice, configureStore } from '@reduxjs/toolkit';
import dummyItems from '../helpers/dummyItems';

const initialMovementsState = {
  movements: dummyItems,
};

const movementsSlice = createSlice({
  name: 'movements',
  initialState: initialMovementsState,
  reducers: {
    add(state, action) {
      state.movements = [action.payload, ...state.movements];
    },
    delete(state, action) {
      const id = action.payload;
      state.movements = state.movements.filter(mov => mov.id !== id);
    },
  },
});

//AUTHORIZATION
const initialAuthState = {
  isAuthenticated: false,
};

const authSlice = createSlice({
  name: 'auth',
  initialState: initialAuthState,
  reducers: {
    login(state) {
      state.isAuthenticated = true;
    },
    logout(state) {
      state.isAuthenticated = false;
    },
  },
});

//MIDDLEWARE
const localStorageMiddleware = ({ getState }) => {
  return next => action => {
    const result = next(action);
    localStorage.setItem('applicationState', JSON.stringify(getState()));
    return result;
  };
};

const reHydrateStore = () => {
  if (localStorage.getItem('applicationState') !== null) {
    return JSON.parse(localStorage.getItem('applicationState')); // re-hydrate the store
  }
};

//STORE CONFIGURATION
const store = configureStore({
  reducer: {
    movements: movementsSlice.reducer,
    auth: authSlice.reducer,
  },
  preloadedState: reHydrateStore(),
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware().concat(localStorageMiddleware),
});

export const movementsActions = movementsSlice.actions;
export const authActions = authSlice.actions;

export default store;
dohp0rv5

dohp0rv53#

您必须dispatchloginlogout操作才能实际更改redux存储中的状态!

相关问题