新建的一个react项目需要用到状态管理&&持久化存储,在这里使用redux封装一下
安装的包
pnpm i react-redux redux-persist @reduxjs/toolkit
目录结构
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 可以在页面使用添加代码提示
如