优秀的编程知识分享平台

网站首页 > 技术文章 正文

react状态管理器@reduxjs/toolkit、react-redux、redux-persist

nanyue 2024-09-01 20:30:08 技术文章 4 ℃

react PC端项目构建TS,react@18.2.0+antd+vite+axios+redux+sass+ts 完整版代码下载:

reactPC端项目构建TS,react@18.2.0+antd+vite+axios+redux+sass+ts资源-CSDN文库

react PC端项目构建,react@18.2.0+antd+vite+axios+redux+sass完整版代码下载:

reactPC端项目构建,react@18.2.0+antd+vite+axios+redux+sass资源-CSDN文库

react移动端项目构建TS,react@18.2.0+react-vant+vite+axios+redux+sass+ts完整版代码下载:

react移动端项目构建TS,react@18.2.0+react-vant+vite+axios+redux+sass+ts资源-CSDN文库

react移动端项目构建,react@18.2.0+react-vant+vite+axios+redux+sass完整版代码下载:

react移动端项目构建,react@18.2.0+react-vant+vite+axios+redux+sass资源-CSDN文库

一、简介

React Redux 是一个用于 React 应用程序的状态管理库。它帮助您管理应用程序的状态并使状态在应用程序中的组件之间共享和访问变得更容易。

以下是 React Redux 的一些主要概念和工作原理:

  1. 状态管理:React 应用程序中的状态通常存储在组件的本地状态中。但是,当应用程序变得复杂时,需要共享状态并使其在多个组件之间保持同步。React Redux 允许您将应用程序的状态存储在一个全局的状态树中,称为 Store。
  2. Store:Store 是应用程序中存储状态的单一来源。您可以通过 Redux 创建一个 Store,并将其与 React 应用程序集成。Store 中的状态可以被任何组件访问,但只能通过派发(dispatch)动作来修改状态。
  3. 动作(Actions):动作是描述状态变化的纯粹 JavaScript 对象。在 React Redux 中,通过派发动作来更新状态。动作必须包含一个type 属性来描述动作的类型,以及其他可选的数据。
  4. Reducer:Reducer 是一个纯函数,它接收先前的状态和一个动作,并返回新的状态。Reducer 定义了状态树如何响应不同类型的动作。
  5. 连接(Connect):React 组件可以通过连接函数 connect 与 Redux Store 连接。这个连接函数将组件与 Store 中的状态和派发动作连接起来,使组件能够访问状态并派发动作。
  6. Provider:React Redux 提供了一个 Provider 组件,它使 React 组件树中的所有组件都能够访问 Redux Store。通过在应用程序的最顶层使用 Provider,可以确保整个应用程序都能够访问到 Redux 的状态。

二、配置状态管理器,需安装@reduxjs/toolkit、react-redux、redux-persist

  1. demoStore.js
import {createSlice} from "@reduxjs/toolkit";
import {persistReducer} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

const demoStore = createSlice({
    name: 'demoStore',
    initialState: {
        userId: '213213',
        userName: '张三'
    },
    reducers: {
        updateState(state, action) {
            return {
                ...state,
                ...action.payload
            }
        }
    }
});

const persistConfig = {
    key: 'demoStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const demoStorePersist = persistReducer(persistConfig, demoStore.reducer);

export default demoStorePersist;
export const demoStoreAction = demoStore.actions;
  1. redux.js
import {configureStore} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist from "@/store/demoStore.js";

export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false})
    },
});
export const persist = persistStore(store);
  1. App.jsx
import RootRouter from "@/router.jsx";
import {Provider} from "react-redux";
import {PersistGate} from "redux-persist/integration/react";
import {persist, store} from "@store/redux.js";
import "./App.scss";

function App() {
    return (
        <>
            <Provider store={store}>
                <PersistGate loading={null} persistor={persist}>
                    <RootRouter/>
                </PersistGate>
            </Provider>
        </>
    )
}

export default App
  1. 使用store
import {useSelector} from "react-redux";

const Home = ()=>{
    const demoeStore = useSelector(state=>state.demoStore);

    return (<>{demoeStore.userName}</>)
}

export default Home;

三、@reduxjs/toolkit创建store:configureStore(options)

  1. reducer:定义用作根reducer的单个reducer函数,或作为传递给combineReducers()的slice reducers对象。
  2. middleware:中间件数组,用于安装中间件。或者接收getDefaultMiddleware参数并返回中间件Tuple的回调函数。
  3. devTools:是否启用Redux DevTools集成,默认为true。可以通过传递Redux DevTools选项进行额外配置。
  4. preloadedState:要传递给 Redux 函数的可选初始状态值,与Redux的createStore相同。
  5. enhancers:用于自定义增强器数组。
import {configureStore} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist from "@/store/demoStore.js";

export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false})
    },
});
  1. configureStore(options)返回一个store对象,对象属性如下:
  • store.getState():获取最新的state
  • store.dispatch(action):用于触发action
  • store.subscribe(listener):添加一个监听器,每当 dispatch action 的时候就会执行
  • store.replaceReducer(nextReducer):替换 store 当前用来计算 state 的 reducer

四、@reduxjs/toolkit配置中间件

  1. getDefaultMiddleware(options)获取默认中间件、customMiddleware自定义中间件(js函数柯里化写法)
import {configureStore} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist from "@/store/demoStore.js";

const customMiddleware = (store) => (next) => (action) => {
    console.log('store:',store);
    console.log('next:',next);
    console.log('action:',action)
    return next(action);
};

export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false}).concat(customMiddleware)
    },
});
export const persist = persistStore(store);
  1. getDefaultMiddleware,options参数配置
  • thunk:指定是否启用Thunk中间件,默认为true,用于处理异步操作和dispatch函数。如果是个json对象,则是Thunk中间件配置,配置如下:
extraArgument:额外参数,用于传递给 Redux Thunk 中间件的附加参数。
  • immutableCheck:指定是否启用不可变性检查,默认为true,用于检查状态是否被修改。如果是个json对象,则是不可变性检查配置,配置如下:
isImmutable:用于检查值是否被视为不可变的回调函数。该函数会递归应用于状态中包含的每个值。默认实现将对基本类型(如数字、字符串、布尔值、null 和 undefined)返回 true。
ignoredPaths:一个由点分隔的路径字符串数组,用于匹配从根状态到要忽略的命名节点的路径,以便在检查不可变性时忽略这些节点。默认为 undefined。
warnAfter:如果检查花费的时间超过 N 毫秒,则打印警告。默认值为 32 毫秒。
  • serializableCheck:指定是否启用可序列化性检查,默认为true,用于检查action和state是否可以被序列化。如果是个json对象,则是可序列化性检查配置,配置如下:
isSerializable:用于检查值是否被视为可序列化的函数。该函数会递归应用于状态中包含的每个值。默认为 isPlain()。
getEntries:用于从每个值中检索条目的函数。如果未指定,将使用 Object.entries。默认为 undefined。
ignoredActions:在检查可序列化性时要忽略的动作类型数组。默认为 []。
ignoredActionPaths:在检查可序列化性时要忽略的点分隔路径字符串或正则表达式数组。默认为 ['meta.arg', 'meta.baseQueryMeta']。
ignoredPaths:在检查可序列化性时要忽略的点分隔路径字符串或正则表达式数组。默认为 []。
warnAfter:执行时间警告阈值。如果中间件花费的时间超过 warnAfter 毫秒,则在控制台中显示警告。默认为 32 毫秒。
ignoreState:选择不检查状态。当设置为 true 时,将忽略其他与状态相关的参数。
ignoreActions:选择不检查动作。当设置为 true 时,将忽略其他与动作相关的参数。
disableCache:选择不缓存结果。缓存使用 WeakSet 并加快重复检查过程。如果浏览器不支持 WeakSet,则自动禁用缓存。
  • actionCreatorCheck:指定是否启用action创建者检查,默认为true,用于检查是否正确使用了action创建函数。如果是个json对象,则是action创建者检查配置,配置如下:
isActionCreator:用于识别值是否为动作创建器的函数。默认情况下检查具有静态类型属性和匹配方法的函数。

五、@reduxjs/toolkit配置监听中间件

  1. createListenerMiddleware(option) 创建监听中间件,当调用demoStoreAction.updateState时会进入effect函数,option参数配置如下:
  • extra: 额外参数,用于传递额外的参数给监听中间件。
  • onError: 错误处理函数,用于接收由监听器(listener)和监听器选项(listenerOption.predicate)引发的同步错误。
import {configureStore, createListenerMiddleware} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist, {demoStoreAction} from "@/store/demoStore.js";

const listenerMiddleware = createListenerMiddleware()

listenerMiddleware.startListening({
    actionCreator: demoStoreAction.updateState,
    effect: async (action, listenerApi) => {
        console.log(action,listenerApi)
    },
})

export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false}).prepend(listenerMiddleware.middleware)
    },
});
export const persist = persistStore(store);
  1. listenerMiddleware.middleware:获取监听中间件实例
  2. listenerMiddleware.startListening(option):向中间件添加新的侦听器
  • type: 精确的动作类型字符串匹配,用于指定要匹配的动作类型字符串。
  • actionCreator: 基于 RTK 动作创建者的精确动作类型匹配,用于指定要匹配的 RTK 动作创建者。
  • matcher: 使用 RTK 匹配器匹配多个动作中的一个,用于指定要匹配的匹配器。
  • predicate: 基于动作 + 状态的组合返回 true,用于指定要匹配的断言。
  • effect: 当匹配到动作时要运行的实际回调函数,接收动作和监听器 API 作为参数,可以是同步函数或返回 Promise 的异步函数
  1. listenerMiddleware.stopListening(option):删除给定的侦听器
  • type: 精确的动作类型字符串匹配,用于指定要匹配的动作类型字符串。
  • actionCreator: 基于 RTK 动作创建者的精确动作类型匹配,用于指定要匹配的 RTK 动作创建者。
  • matcher: 使用 RTK 匹配器匹配多个动作中的一个,用于指定要匹配的匹配器。
  • predicate: 基于动作 + 状态的组合返回 true,用于指定要匹配的断言。
  • effect: 当匹配到动作时要运行的实际回调函数,接收动作和监听器 API 作为参数,可以是同步函数或返回 Promise 的异步函数
  • cancelActive:配置用于指示监听器是否应该在触发后取消激活状态
  1. listenerMiddleware.clearListeners(option):删除所有当前侦听器条目。还会取消这些侦听器的所有活动运行实例。

六、@reduxjs/toolkit配置动态中间件:允许在存储初始化后将中间件添加到调度链

  1. createListenerMiddleware() 创建动态中间件
import {configureStore, createDynamicMiddleware} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist from "@/store/demoStore.js";

const dynamicMiddleware = createDynamicMiddleware()
export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false}).prepend(dynamicMiddleware.middleware)
    },
});
export const persist = persistStore(store);
  1. dynamicMiddleware.middleware:获取动态中间件实例
  2. addMiddleware:将一组中间件注入到实例中
addMiddleware(logger, listenerMiddleware.instance)
  1. withMiddleware接受一组中间件并创建一个操作
const listenerDispatch = store.dispatch(  withMiddleware(listenerMiddleware.middleware),)
const unsubscribe = listenerDispatch(addListener({ type, effect }))

七、@reduxjs/toolkit配置增强器

  1. getDefaultEnhancers(options)获取默认增强器
import {configureStore} from "@reduxjs/toolkit";
import {persistStore} from "redux-persist";
import demoStorePersist from "@/store/demoStore.js";

const customEnhancer = createStore => (reducer, preloadedState, enhancer) => {
    const store = createStore(reducer, preloadedState, enhancer);
    console.log(store)
    return store;
};
export const store = configureStore({
    reducer: {
        demoStore: demoStorePersist,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false})
    },
    enhancers: (getDefaultEnhancers) =>{
        return  getDefaultEnhancers().concat(customEnhancer)
    }
});
export const persist = persistStore(store);
  1. getDefaultEnhancers,配置项
  • autoBatch:是否自动批处理。如果是个json对象,则是批处理配置
{ type: 'tick' }:使用tick类型启用自动批处理,此选项通过在下一个微任务队列中处理状态更新来实现批处理。
{ type: 'timer', timeout: number }:使用timer类型启用自动批处理,并指定延迟时间(以毫秒为单位),在指定时间内收集状态更新操作并批量处理。
{ type: 'raf' }:使用raf类型启用自动批处理,此选项通过requestAnimationFrame在下一帧中处理状态更新来实现批处理。
{ type: 'callback', queueNotification: (notify: () => void) => void }:使用callback类型启用自动批处理,并提供一个回调函数来处理状态更新的通知。

八、@reduxjs/toolkit创建reducer

  1. createReducer创建reducer,createAction创建action
import {configureStore, createReducer,createAction} from "@reduxjs/toolkit";
import {persistReducer, persistStore} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

const initialState = {
    demoStore:{
        userId: '213213',
        userName: '张三'
    }
};

const updateStateAction = createAction('updateState')

const reducer = createReducer(initialState, (builder)=>{
    builder.addCase(updateStateAction,(state,action)=>{
        console.log(state,action)
        return {
            demoStore:{
                ...state,
                ...action.payload
            }
        }
    })
})

const persistConfig = {
    key: 'root',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const reducerPersist = persistReducer(persistConfig, reducer);

export const store = configureStore({
    reducer: reducerPersist,
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware({serializableCheck: false})
    },
});
export const persist = persistStore(store);
import {useSelector} from "react-redux";
import {store} from "@store/redux.js";

const Home = () => {
    const demoeStore = useSelector(state => state.demoStore);
    const onCLick = ()=>{
        store.dispatch({type:'updateState',payload:{userName:'李四'}})
    }

    return (<>
        <button onClick={onCLick}>点击</button>
        <div>{demoeStore.userName}</div>
    </>)
}

export default Home;
  1. createReducer(initialState,mapOrBuilderCallback):创建reducer
  • initialState:初始化状态
  • mapOrBuilderCallback:接收构建器对象以通过调用定义 case 添加action的处理函数
createReducer({}}, (builder)=>{
    builder
    .addCase(actionCreator,(state,action)=>{}) //添加一个action处理函数,actionCreator普通字符串或者createAction创建的对象
    .addMatcher((action) => action.type.endsWith('update'),(state,action)=>{}) //匹配对应的action,所有末尾是update都会进入该函数
    .addDefaultCase((state,action)=>{}) //默认action处理函数
})
  1. createAction(type, prepareAction):createAction创建action
  • type:action类型
  • prepareAction:action创建函数
import { createAction} from '@reduxjs/toolkit'

const addTodo = createAction('todos/add', (payload)=>{
  return {
    payload: {
      ...payload,
      id: 213213,
      createdAt: new Date().toISOString(),
    },
  }
})

九、@reduxjs/toolkit创建切片:createSlice

createSlice是模块化管理store,createReducer是把store集中一起管理。createSlice案例可看步骤2

  1. createSlice(option):创建切片,option配置如下
  • name:用于生成 action 类型的名称。
  • initialState:reducer 的初始状态。
  • extraReducers:用于添加更多的 reducers。
  • reducerPath:slice reducer 的位置偏好,被 combineSlices 和 slice.selectors 使用。默认为 name。
  • selectors:包含 selectors 对象,接收 slice 的状态作为第一个参数。
  • reducers:包含“case reducers”对象。键名将用于生成 actions。除了示例中json,reducers还可以是个函数
import {createSlice} from "@reduxjs/toolkit";
import {persistReducer} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

const demoStore = createSlice({
    name: 'demoStore',
    initialState: {
        userId: '213213',
        userName: '张三'
    },
    reducers: (create) => ({
        //create.reducer标准的action函数
        updateState: create.reducer((state, action) => {
            return {
                ...state,
                ...action.payload
            }
        }),
        //create.preparedReduce预处理action函数,第一个参数为预处理函数,第二个参数等同于create.reducer
        preparedState: create.preparedReducer(
            (payload) => {
                return {
                    payload: {
                        userId: '213213',
                        userName: '张三',
                        ...payload
                    }
                }
            },
            (state, action) => {
                return {
                    ...state,
                    ...action.payload
                }
            }
        ),
    })
});

const persistConfig = {
    key: 'demoStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const demoStorePersist = persistReducer(persistConfig, demoStore.reducer);

export default demoStorePersist;
export const demoStoreAction = demoStore.actions;
  1. 使用异步action,内置的 createSlice 不支持 create.asyncThunk,需使用buildCreateSlice重新创建个Slice
import {buildCreateSlice,asyncThunkCreator} from "@reduxjs/toolkit";
import {persistReducer} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

const createDemoSlice = buildCreateSlice({
    creators: { asyncThunk: asyncThunkCreator },
});

const demoStore = createDemoSlice({
    name: 'demoStore',
    initialState: {
        userId: '213213',
        userName: '张三'
    },
    reducers: (create) => ({
        //create.reducer标准的action函数
        updateState: create.reducer((state, action) => {
            return {
                ...state,
                ...action.payload
            }
        }),
        fetchState: create.asyncThunk(
            async (asyncPar, thunkApi) => {
                const res = await fetch('https://randomuser.me/api/');
                return await res.json()
            },
            {
                pending: (state) => {
                    console.log('数据获取中:',state)
                    state.loading = true;
                },
                rejected: (state, action) => {
                    console.log('数据获取失败:',state)
                    state.loading = false;
                },
                fulfilled: (state, action) => {
                    console.log('数据获取成功:',state,action)
                    state.loading = false;
                    state.userName = '异步action'
                },
            }
        ),
    })
});

const persistConfig = {
    key: 'demoStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const demoStorePersist = persistReducer(persistConfig, demoStore.reducer);

export default demoStorePersist;
export const demoStoreAction = demoStore.actions;
  1. 配置extraReducers,额外的reducer可以处理来自其他Slice的action或其他非标准的action类型。示例中的updateName 即可给demoStore使用,又可以给其他store使用
import {createSlice,createAction} from "@reduxjs/toolkit";
import {persistReducer} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

const updateName = createAction('updateName')

const demoStore = createSlice({
    name: 'demoStore',
    initialState: {
        userId: '213213',
        userName: '张三'
    },
    extraReducers: (builder) => {
        builder.addCase(updateName, (state, action) => {
            console.log(state, action)
            state.name = '王五'
        })
    }
});

const persistConfig = {
    key: 'demoStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const demoStorePersist = persistReducer(persistConfig, demoStore.reducer);

export default demoStorePersist;
export const demoStoreAction = demoStore.actions;
import {useSelector} from "react-redux";
import {store} from "@store/redux.js";

const Home = () => {
    const demoeStore = useSelector(state => state.demoStore);

    const onCLick = ()=>{
        store.dispatch({type:'updateName',payload:{userName:'李四'}})
    }

    return (<>
        <button onClick={onCLick}>点击</button>
        <div>{demoeStore.userName}</div>
    </>)
}

export default Home;
  1. createSlicec创建之后将返回如下属性
  • name: string:slice 的名称。
  • reducer: ReducerFunction:slice 的 reducer 函数,用于处理 action 和更新 state。
  • actions: Record:包含所有 action creators 的对象,以 action 名称作为键。
  • caseReducers: Record:包含所有 case reducers 的对象,以 action 名称作为键。
  • getInitialState: () => State:返回 slice 的初始状态的函数。
  • reducerPath: string:slice reducer 在 Redux store state 中的路径。
  • selectSlice: Selector:用于选择当前 slice state 的 selector 函数。
  • selectors: Record:包含所有 selectors 的对象,以 selector 名称作为键。
  • getSelectors: (selectState: (rootState: RootState) => State) => Record:返回一个包含所有 selectors 的对象的函数。
  • injectInto: (injectable: Injectable, config?: InjectConfig & { reducerPath?: string }) => InjectedSlice:用于将 slice 注入到另一个对象中的方法。

十、@reduxjs/toolkit创建异步的Thunk:createAsyncThunk

import {createSlice, createAsyncThunk} from "@reduxjs/toolkit";
import {persistReducer} from "redux-persist";
import sessionStorage from "redux-persist/es/storage/session";

export const updateName = createAsyncThunk(
    'updateName',
    async (asyncPar ,thunkAPI) => {
        console.log(asyncPar)
        const response = await fetch('https://randomuser.me/api/')
        return await response.json()
    }
)

const demoStore = createSlice({
    name: 'demoStore',
    initialState: {
        userId: '213213',
        userName: '张三'
    },
    extraReducers: (builder) => {
        builder.addCase(updateName.fulfilled, (state, action) => {
            console.log(state, action)
            state.name = '王五'
        })
    }
});

const persistConfig = {
    key: 'demoStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const demoStorePersist = persistReducer(persistConfig, demoStore.reducer);

export default demoStorePersist;
export const demoStoreAction = demoStore.actions;
import {useSelector} from "react-redux";
import {store} from "@store/redux.js";
import {updateName} from "@store/demoStore.js";

const Home = () => {
    const demoeStore = useSelector(state => state.demoStore);

    const onCLick = ()=>{
        store.dispatch(updateName({name:'李四'}))
    }

    return (<>
        <button onClick={onCLick}>点击</button>
        <div>{demoeStore.userName}</div>
    </>)
}

export default Home;
  1. fetchUserById. = createAsyncThunk(type,payloadCreator,options):创建异步thunk
  • type将用于生成附加 Redux 操作类型常量的字符串
  • payloadCreator:异步函数
  • options:createAsyncThunk配置
condition(arg, { getState, extra } ):如果需要,可用于跳过有效负载创建者和所有操作分派的执行的回调。有关完整说明,请参阅执行前取消。
dispatchConditionRejection:如果condition()返回false,默认行为是根本不会调度任何操作。如果您仍然希望在取消 thunk 时调度“拒绝”操作,请将此标志设置为true。
idGenerator(arg):生成请求序列时使用的函数。默认使用nanoid,但您可以实现自己的 ID 生成逻辑。
serializeError(error: unknown):用您自己的序列化逻辑替换内部方法。
getPendingMeta({ arg, requestId }, { getState, extra }): 创建将合并到字段中的对象的函数pendingAction.meta。
  1. createAsyncThunk(type,payloadCreator,options)返回结果
  • fetchUserById.pending:是否进行中,可用作 builder.addCase的action
  • fetchUserById.fulfilled:是否已完成,可用作 builder.addCase的action
  • fetchUserById.rejected:是否失败,可用作 builder.addCase的action

十一、@reduxjs/toolkit创建选择器createSelector

在 Redux 应用中,当 Redux store 中的 state 发生变化时,即使输入参数没有发生变化,selector 函数都会重新计算。这可能导致不必要的性能损耗。createSelector 提供了记忆功能,它会缓存上一次的输入参数和计算结果。当输入参数没有发生变化时,createSelector 会返回缓存的计算结果,而不会重新计算。这样可以避免不必要的计算,提高应用的性能。

  1. 新增studentStore.js
import { createSlice } from '@reduxjs/toolkit'
import sessionStorage from "redux-persist/es/storage/session";
import {persistReducer} from "redux-persist";

const studentStore = createSlice({
    name: "student",
    initialState: {
        age: 18
    },
    reducers: {
        addAge: (state)=>{
            state.age+=1
        }
    }
})

const persistConfig = {
    key: 'studentStore',
    storage: sessionStorage,
    serialize: (data) => {//自定义储存数据
        if (data._persist) {
            return JSON.stringify(data);
        } else {
            return data
        }
    },
    deserialize: (data) => {
        try {
            return JSON.parse(data);
        } catch (e) {
            return data;
        }
    }
};

const studentStorePersist = persistReducer(persistConfig, studentStore.reducer);

export default studentStorePersist;
export const studentStoreAction = studentStore.actions;
  1. 场景复现,如下图可知每次更新studentStore时demoeStore的useSelector都会重新进入,如果该useSelector有复杂的计算。那么对性能会有一定的损耗
import {useSelector} from "react-redux";
import {store} from "@store/redux.js";
import {useEffect} from "react";
import {studentStoreAction} from "@store/studentStore.js";

const Home = () => {
    const demoeStore = useSelector(state=>{
        console.log('studentStore更新,不应该进入该函数')
        return state.demoStore
    });
    const studentStore = useSelector(state=>state.studentStore);

    useEffect(() => {
        console.log('demoeStore更新')
    }, [demoeStore]);

    useEffect(() => {
        console.log('studentStore更新')
    }, [ studentStore]);

    const onCLick = () => {
        store.dispatch(studentStoreAction.addAge())
    }

    return (<>
        <button onClick={onCLick}>点击</button>
        <div>学生年龄:{studentStore.age}</div>
    </>)
}

export default Home;
  1. 使用createSelector,如下图可知每次更新studentStore时不会在进入demoeStore的useSelector
import {useSelector} from "react-redux";
import {store} from "@store/redux.js";
import {useEffect} from "react";
import {studentStoreAction} from "@store/studentStore.js";
import {createSelector} from "@reduxjs/toolkit";

const demoeSelector = createSelector(
    (state) => state.demoStore,
    (demoStore) => {
        console.log('studentStore更新,不应该进入该函数')
        return {
            userId: demoStore.userId,
            userName:  demoStore.userName
        }
    }
);

const Home = () => {
    const demoeStore = useSelector(demoeSelector);
    const studentStore = useSelector(state => state.studentStore);

    useEffect(() => {
        console.log('demoeStore更新')
    }, [demoeStore]);

    useEffect(() => {
        console.log('studentStore更新')
    }, [studentStore]);

    const onCLick = () => {
        store.dispatch(studentStoreAction.addAge())
    }

    return (<>
        <button onClick={onCLick}>点击</button>
        <div>学生年龄:{studentStore.age}</div>
    </>)
}

export default Home;

十二、@reduxjs/toolkit其他Api

  1. createEntityAdapter:创建实体适配器
import {
  createEntityAdapter,
  createSlice,
  configureStore,
} from '@reduxjs/toolkit'

const booksAdapter = createEntityAdapter({
 
  selectId: (book) => book.bookId,

  sortComparer: (a, b) => a.title.localeCompare(b.title),
})

const booksSlice = createSlice({
  name: 'books',
  initialState: booksAdapter.getInitialState(),
  reducers: {

    bookAdded: booksAdapter.addOne,
    booksReceived(state, action) {
  
      booksAdapter.setAll(state, action.payload.books)
    },
  },
})

const store = configureStore({
  reducer: {
    books: booksSlice.reducer,
  },
})

console.log(store.getState().books)
// { ids: [], entities: {} }


const booksSelectors = booksAdapter.getSelectors((state) => state.books)


const allBooks = booksSelectors.selectAll(store.getState())
  1. combineSlices:合并切片
import { combineSlices } from '@reduxjs/toolkit'
import { api } from './api'
import { userSlice } from './users'

export const rootReducer = combineSlices(api, userSlice)



import { configureStore } from '@reduxjs/toolkit'
import { rootReducer } from './slices'

export const store = configureStore({
  reducer: rootReducer,
})

十三、react-redux组件之Provider

Provider组件使 Reduxstore可供任何需要访问 Redux 存储的嵌套组件使用,详细使用可参考步骤2,相关属性如下:

  1. store: Redux 应用中的单一存储对象。这个属性用于传递 Redux store 给Provider组件,以便整个应用都能访问到 Redux store 中的状态和操作方法。
  2. serverState:可选属性,表示服务器端状态快照。如果在服务器端渲染时提供了此状态快照,它将在初始渲染期间使用,以确保 UI 输出与服务器端生成的 HTML 保持一致。这个属性是在 React-Redux 8.0 版本中新增的功能。
  3. context: 可选属性,用于在 React-Redux 内部使用的上下文。如果使用了这个属性,需要使用 React.createContext() 创建一个上下文对象,并将其提供给Provider组件。如果提供了上下文,需要在 connect 中自定义以匹配 提供的上下文。初始值应设置为 null,如果Provider没有覆盖它,hooks 将会报错。
  4. stabilityCheck:用于 useSelector 稳定性检查的全局配置。useSelector 是 React-Redux 中用于选择 Redux store 中的部分状态的钩子函数。这个属性允许对 useSelector 的稳定性检查进行全局配置。
  5. children:React 组件树中的顶层 React 元素,例如<App/> 。这是Provider的必需属性,它表示 组件的子元素,即整个应用的根组件。children 属性用于包裹整个应用,使得应用中的所有组件都能够访问 Redux store 中的状态。

十四、react-redux相关hook、api

  1. useSelector((state)=>state.demoStore,options):从 Redux 存储状态中提取数据以供此组件使用,options配置如下
  • equalityFn:用于指定用于比较前后两次选择器函数计算结果是否相等的函数。当状态发生变化时,React-Redux 使用这个函数来判断是否触发组件的重新渲染
  • devModeChecks:用于配置开发模式下的检查频率
stabilityCheck:用于配置在开发模式下对 useSelector 的稳定性检查的频率。可以设置为 'never'(从不检查)、'once'(仅检查一次)或 'always'(始终检查)。
identityFunctionCheck:用于配置在开发模式下对选择器函数的身份函数检查的频率。类似地,可以设置为 'never'、'once' 或 'always'。身份函数检查用于检测选择器函数是否返回了其输入参数,这可能导致性能问题。
  1. useDispatch():用于在函数组件中获取 Redux store 的 dispatch 方法。通过 useDispatch(),函数组件可以方便地触发 Redux store 中的 action
  2. useStore():返回引用的store
  3. batch((fn: () => void)):自动批处理所有状态更新;如果您使用的是 React 18,则不需要使用batchAPI。React 18 会自动批处理所有状态更新
import { batch } from 'react-redux'

function myThunk() {
  return (dispatch, getState) => {
    // should only result in one combined re-render, not two
    batch(() => {
      dispatch(increment())
      dispatch(increment())
    })
  }
}

十五、redux-persist持久化储存

  1. persistReducer(config, reducer):创建一个经过持久化处理的 Redux reducer,config配置如下
  • version:用于指定持久化存储中的版本号。
  • storage:必需属性,表示要使用的持久化存储引擎,如 localStorage 或 AsyncStorage。
  • key:必需属性,表示存储数据时使用的键值。
  • keyPrefix:已弃用,在 v6 版本中将被移除。之前用于指定存储键的前缀。
  • blacklist:指定不需要持久化的状态属性数组。
  • whitelist:指定需要持久化的状态属性数组。
  • transforms:用于自定义数据转换的数组。
  • throttle:表示在持久化过程中的节流时间间隔。
  • migrate:用于执行数据迁移的函数。
  • stateReconciler:用于控制状态合并的函数或布尔值。
  • getStoredState:用于获取存储状态的函数,返回一个 Promise。
  • debug:是否启用调试模式。
  • serialize:是否序列化存储数据,可以是布尔或函数,函数时用于自定义数据转换
  • deserialize:读取储存数据,函数,自定义读取数据时的数据转换,当serialize是函数时,需要使用deserialize进行数据读取转换
  • timeout:持久化操作的超时时间。
  • writeFailHandler:用于处理持久化写入失败的错误处理函数。
  1. persistStore(store, config, callback):用于将 Redux store 与持久化存储进行连接,并初始化持久化功能
  • store:Redux store 对象,即应用程序中创建的 Redux store。
  • config:persistStore配置对象。
  • callback:用于在持久化初始化完成后执行一些额外的操作
  1. persistStore(store, config, callback)返回persistor对象,对象具有的属性如下:
  • persistor.purge():从磁盘清除状态并返回承诺
  • persistor.flush():立即将所有挂起状态写入磁盘并返回承诺
  • persistor.pause():暂停持久性
  • persistor.persist():恢复坚持
最近发表
标签列表