next借助redux/toolkit 和 redux-persist 实现数据持久化

453 阅读2分钟

image.png

# 前言

    在我们使用react中虽然可以借助useState 或者 useReducer 进行数据管理,但如果在多页面共享数据我们就需要借助props来传递数据,该方法虽然能解决问题但难免使页面变得复杂难以维护,因此出现了很多状态管理的库,其中最出名的当属redux,借助 state 和 dispatch 进行数据的维护。

# REACT常用状态管理库

  1. react-redux[(React Redux 中文文档 | React Redux 中文文档 (react-redux.js.org))](url)
  2. zustant [ZUSTAND 中文文档 | ZUSTAND (awesomedevin.github.io)](url)
  3. mobx [1. MobX 介绍 · MobX 中文文档](url)

# 如何选择?

    react-redux 坐拥强大的社区深受全世界的喜爱,许多开发问题都可以在社区找到答案,缺点就是过于笨重,每个状态都需要配置state 和 reducer。

# 持久化配置库

yarn add @reduxjs/toolkit react-redux redux-persist

# 配置方式

store/user_slice.ts

"""
定义用户状态
"""
import {createSlice} from '@reduxjs/toolkit'


enum Gender {
    male,
    female,
    other
}
interface UserState {
    value: {
        user_id: number,
        username: string,
        email: string,
        full_name: string,
        display_name: string,
        avatar: string,
        introduction: string,
        gender: Gender.male | Gender.female | Gender.other,
        birth_date: string,
        user_role: string[]
    }
}

const initialState: UserState = {
    value: {
        user_id: 0,
        username: "",
        email: "",
        full_name: "",
        display_name: "未登录用户",
        avatar: "",
        introduction: "",
        gender: Gender.other,
        birth_date: "",
        user_role: []
    }
}

export const userSlice = createSlice({
    name: "user",
    initialState,
    reducers: {
        login: (state, action) => {
            return Object.assign({}, state, action.payload)
        },
        logout: (state) => {
            state.value = initialState.value
        },
    },
})
export const {login, logout} = userSlice.actions
export default userSlice.reducer

store.ts

"use client";

import {combineReducers, configureStore} from '@reduxjs/toolkit'
import userReducer from "@/store/user_slice"
import {persistReducer} from 'redux-persist';
import createWebStorage from "redux-persist/lib/storage/createWebStorage";

const reducers = combineReducers({
    user: userReducer
})


const createNoopStorage = () => {
    return {
        getItem(_key: any) {
            return Promise.resolve(null);
        },
        setItem(_key: any, value: any) {
            return Promise.resolve(value);
        },
        removeItem(_key: any) {
            return Promise.resolve();
        },
    };
};

const storage =
    typeof window !== "undefined"
        ? createWebStorage("local")
        : createNoopStorage();

const persistConfig = {
    key: 'root',
    storage,
};

const persistedReducer = persistReducer(persistConfig, reducers);

export const makeStore = () => {
    return configureStore({
        reducer: persistedReducer,
        devTools: process.env.NODE_ENV !== 'production',
    })
}


// Infer the type of makeStore
export type AppStore = ReturnType<typeof makeStore>
// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<AppStore['getState']>
export type AppDispatch = AppStore['dispatch']

hooks

import type {TypedUseSelectorHook} from 'react-redux'
import {useDispatch, useSelector, useStore} from 'react-redux'
import type {AppDispatch, AppStore, RootState} from './store'

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector
export const useAppStore: () => AppStore = useStore

storeProvider

"use client"

import {ReactNode, useRef} from 'react'
import {Provider} from 'react-redux'
import {PersistGate} from 'redux-persist/integration/react';
import {AppStore, makeStore} from '@/lib/store'
import {persistStore} from 'redux-persist';

export default function StoreProvider({ children }: { children: ReactNode }) {
    const storeRef = useRef<AppStore>()
    const persistor = useRef<any>()
    if (!storeRef.current) {
        storeRef.current = makeStore()
        persistor.current = persistStore(storeRef.current)
    }


    return (
        <Provider store={storeRef.current}>
            <PersistGate loading={null} persistor={persistor.current}>
                {children}
            </PersistGate>
        </Provider>)
}
配置完毕后可以借助浏览器redux-devtools查看数据是否被缓存
import {
useAppDispatch,
useAppSelector
} from "hooks"
const user = useAppSelector((state) => state.user.value)
const dispatch = useAppDispatch()

除了使用redux 进行状态管理外如果希望全局共享的数据很少大家也可以借助 ahooks的 useLocalstorage 也是很好的方法。

ahooks [useUpdateLayoutEffect - ahooks 3.0](url)