如何保持一个redux slice在注销时不被清除?

6qftjkof  于 6个月前  发布在  其他
关注(0)|答案(2)|浏览(61)

我有一个React Native应用程序(使用TypeScript和Redux-Toolkit(RTK)Query),我想只在第一次启动应用程序时显示一个介绍滑块,除非应用程序数据被清除,否则永远不会再次显示它。我已经为它的visibility状态创建了一个切片,并使用redux-persist来保存数据。
在注销时,我按照Dan Abramov和伦茨韦伯-特龙的建议重置存储和持久化状态。

// Root reducer (resettable)
const rootReducer = (
  state: ReturnType<typeof appReducer> | undefined,
  action: AnyAction
) => {
  // If the `logout` action is dispatched, clean the `Redux Persist` storage and reset the state
  if (action.type === "auth/logout") {
    storage.removeItem("persist:root");

    return appReducer(undefined, action);
  }

  return appReducer(state, action);
};

字符串
我还分离了intro切片的persistence配置,以便将其保存到存储中。

// Root persistence config
const rootPersistConfig = {
  key: "root",
  version: 1,
  storage,
  blacklist: ["intro", api.reducerPath],
};

// Intro slides persistence config
const introPersistConfig = {
  key: "intro",
  version: 1,
  storage,
  blacklist: [api.reducerPath],
};
    
// Top-level reducers
const appReducer = combineReducers({
  [api.reducerPath]: api.reducer,
  auth: authSliceReducer,
  intro: persistReducer(introPersistConfig, introSliceReducer),
});


这是intro切片:

interface IntroSliceState {
  /** Whether to show the app intro slides or not */
  showIntro: boolean;
}

const initialState: IntroSliceState = {
  showIntro: true,
};

const introSlice = createSlice({
  name: "intro",
  initialState,
  reducers: {
    hideIntro: (state) => {
      state.showIntro = false;
    },
  },
});


我现在试图解决的问题是找到一种方法来保持intro片在注销时被清除,我知道我必须修改这部分:return appReducer(undefined, action);,但我不知道如何做到这一点。

hmae6n7t

hmae6n7t1#

与其将未定义的状态传递给reducer,从而从初始状态重新计算整个状态树,不如计算一个新的状态对象,只保留您想要保留的状态。
范例:

// Root reducer (resettable)
const rootReducer = (
  state: ReturnType<typeof appReducer> | undefined,
  action: AnyAction
) => {
  // If the `logout` action is dispatched, clean the `Redux Persist`
  // storage and reset the state
  if (action.type === "auth/logout") {
    storage.removeItem("persist:root"); // *

    // Keep intro state from previous state
    const { intro } = state;
    // Create new state with retain previous state values
    const nextState = {
      intro,
    };

    return appReducer(nextState, action);
  }

  return appReducer(state, action);
};

字符串

  • 注意:storage.removeItem("persist:root");是一种删除持久化状态的方法。另一种是persistor.purge方法“清除存储的状态”。

还要注意,实际上可能不需要手动清除/清除存储,因为在注销和随后的状态更新时,新状态将立即持久化回存储。

egdjgwm8

egdjgwm82#

你有没有试过清除特定的持久性?

storage.removeItem("persist:intro");

字符串
编辑:抱歉,我刚刚看到了黑名单。你还是应该试着把它挑出来,以排除其他可能性
但我可能会建议使用本地存储来保存第一次启动。曾经有AsyncStorage用于react native,但这里有替代方案:
https://reactnative.directory/?search=storage
如果你使用expo,你可以使用:用途:
@react-native-react-storage/react-storage
如果你需要一个第一次启动hook + hook的示例存储帮助器设置发送回复!
编辑2:
useAppHasLaunched

import { useEffect, useState } from 'react'
import { getAsyncStorageItem, storeAsyncStorageItem } from '../utils/asyncStorageHelper'

export const useAppHasLaunched = () => {
  const HAS_LAUNCHED = 'HAS_LAUNCHED'

  const [hasLaunched, setHasLaunched] = useState<boolean>(false)

  useEffect(() => {
    getData()
  }, [])

  const getData = async () => {
    try {
      const hasLaunched = await getAsyncStorageItem(HAS_LAUNCHED)
      if (hasLaunched) {
        setHasLaunched(true)
      } else {
        await storeAsyncStorageItem(HAS_LAUNCHED, 'true')
      }
    } catch (error) {
      console.log('ERROR_GET_LAUNCH_DATA', error)
    }
  }
  return { hasLaunched, setHasLaunched }
}


电子邮件 *

import AsyncStorage from '@react-native-async-storage/async-storage'

export const getAsyncStorageItem = async (key: string) => {
  try {
    const value = await AsyncStorage.getItem(key)
    if (value) return value
  } catch (error) {
    console.log('Error getting data', error)
  }
  return false
}

export const storeAsyncStorageItem = async (key: string, value: string) => {
  try {
    await AsyncStorage.setItem(key, value)
  } catch (error) {
    console.log('Error storing data', error)
  }
}


然后我在我的注销屏幕上使用它:

const { hasLaunched, setHasLaunched } = useAppHasLaunched()


渲染入职屏幕,传入setHasLaunched,并在入职滑块完成或关闭滑块时使用它

{!hasLaunched && <Onboarding setFinishedOnboarding={setHasLaunched} />}

相关问题