redux @reduxjs/toolkit redux-persist的简单封装

239 阅读2分钟

新建的一个react项目需要用到状态管理&&持久化存储,在这里使用redux封装一下

安装的包

pnpm i react-redux redux-persist @reduxjs/toolkit
目录结构

image.png

reducers

/src/store/reducers/menu.reducer.ts

import { createSlice } from '@reduxjs/toolkit'

/**store 默认值 */
export interface IInitialState {
  /**左侧菜单是否折叠 */
  collapse: boolean
}

const initialState: IInitialState = {
  /**左侧菜单是否折叠 */
  collapse: false
}

const menuReducer = createSlice({
  name: 'menu.reducer',
  initialState,
  reducers: {
    /**设置左侧菜单是否折叠 */
    setCollapse: (state, action) => {
      state.collapse = action.payload
    }
  }
})


export default menuReducer

src/store/reducers/user.reducer.ts

import { createSlice } from '@reduxjs/toolkit'

/**store 默认值 */
export interface IInitialState {
  /**用户头像 */
  avatar: string
}

const initialState: IInitialState = {
  /**用户头像 */
  avatar: ''
}

const userReducer = createSlice({
  name: 'user.reducer',
  initialState,
  reducers: {
    /**设置头像 */
    setAvatar: (state, action) => {
      state.avatar = action.payload
    }
  }
})

export default userReducer

src/store/reducers/index.ts

import { combineReducers } from '@reduxjs/toolkit'
import menuReducer from './menu.reducer'
import userReducer from './user.reducer'

const reducers = combineReducers({
  menu: menuReducer.reducer,
  user: userReducer.reducer
})

export const Actions = {
  menu: menuReducer.actions,
  user: userReducer.actions
}

export default reducers

src/store/index.ts

import { configureStore } from '@reduxjs/toolkit'
import { useSelector } from 'react-redux'
import { persistReducer, persistStore } from 'redux-persist'
import storage from 'redux-persist/lib/storage' // 默认使用 localStorage 作为存储介质
import reducers, { Actions } from './reducers'
// 配置 redux-persist 的持久化选项
const persistConfig = {
  key: 'root', // 存储在 localStorage 中的键名
  storage // 使用 localStorage 作为存储介质
}
// 创建一个持久化的 reducer
const persistedReducer = persistReducer(persistConfig, reducers)

export const store = configureStore({
  reducer: persistedReducer,
  middleware: getDefaultMiddleware =>
    getDefaultMiddleware({
      serializableCheck: false
    })
})

export const persistor = persistStore(store)

type IStore = Omit<ReturnType<typeof store.getState>, '_persist'>

export const useStore = <T>(value: (store: IStore) => T) => {
  return useSelector(value)
}

/** redux 封装 */
export default class Store {
  static store = store

  static useStore = useStore

  static actions = Actions

  static dispatch = this.store.dispatch
}


main.tsx

import '@/assets/css/base.css'
import ReactDOM from 'react-dom/client'
import { Provider } from 'react-redux'
import { RouterProvider } from 'react-router-dom'
import { PersistGate } from 'redux-persist/integration/react'
import router from './router'
import { persistor, store } from './store'

ReactDOM.createRoot(document.getElementById('root')!) /** */
  .render(
    <Provider store={store}>
      <PersistGate persistor={persistor}>
        <RouterProvider router={router}></RouterProvider>
      </PersistGate>
    </Provider>
  )


页面使用

aside.tsx


import Store from '@/store'
import { Android, MoreOne } from '@icon-park/react'
import clsx from 'clsx'
import { useEffect, useState } from 'react'

export default function Aside() {
  const [showSpan, setShowSpan] = useState(false)
  const collapse = Store.useStore(state => state.menu.collapse)
  const setCollapse = () => Store.dispatch(Store.actions.menu.setCollapse(!collapse))
  useEffect(() => {
    if (collapse) setShowSpan(false)
    else
      setTimeout(() => {
        setShowSpan(true)
      }, 200)
  }, [collapse])
  return (
    <div
      style={{
        width: collapse ? '50px' : '200px',
        transition: 'width 0.3s ease-in-out',
        height: 'calc(100vh - 48px)'
      }}
      className="flex flex-col"
    >
      <div
        className={clsx(
          'w-full cursor-pointer hover:bg-slate-300 flex items-center justify-center p-3 border-t border-gray-100 static top-0'
        )}
        onClick={setCollapse}
      >
      </div>
    </div>
  )
}


useStore 封装

import { useSelector } from 'react-redux'
type IStore = Omit<ReturnType<typeof store.getState>, '_persist'>
export const useStore = <T>(value: (store: IStore) => T) => {
  return useSelector(value)
}
通过ts类型推断 IStore 可以在页面使用添加代码提示

image.png

image.png

ok