React状态管理库 - redux-toolkit篇

如何实现一个redux-toolkit

  1. 前言

    当我们使用纯redux的时候,我们用createStore创建store,会发现提示

react推荐我们使用"@reduxjs/toolkit"(以下简称rtk)。 实际上rtk是对redux的一层封装。在官方文档中,说"Redux Toolkit 简化了编写 Redux 逻辑和设置 store 的过程。"

我们先来看看rtk如何使用?

  1. 创建counterSlice
js 复制代码
import {createSlice} from '../rtk-nut/createSlice'
const counterSlice = createSlice({
    name:'counter',
    initialState:{value:0},
    reducers:{
        increment:(state)=>{
            state.value += 1
        },
        decrement:(state)=>{
            state.value -= 1
        },
        incrementByAmount:(state,action)=>{
            state.value += action.payload
        }
    }
})
export const {increment, decrement,incrementByAmount} = counterSlice.actions
export default counterSlice.reducer

那么它和redux中的countReducer有什么区别?

js 复制代码
function countReducer(state = 0, action)
{ 
    switch(action.type){ 
    case "ADD": 
        return state + 1 
    case "Minus": 
        return state - 1 
    default: 
    return state 
   } 
}

除了基本的用法之外,我们可以注意到修改状态的方式变了。redux中是返回一个新的状态,而rtk是对状态中的某个值进行修改。这里我们可以理解为(个人理解):redux是函数式的编程思想,rtk像是面向对象的思想。那么为什么可以这么做呢?这实际上是rtk内置了immer,他帮我们在背后进行了state的状态值修改。

设想对于一个复杂的状态,我们想要返回新的状态值会有很多不改变的,也许只有一个改变,那么我们可以很大程度上简化状态修改逻辑。

  1. 创建状态仓库
js 复制代码
export default configureStore({
    reducer:{
        counter: countReducer
    }
})
  1. 在页面中使用rtk
js 复制代码
export default function RtkPage(){
    const [state, setState] = useState(store.getState().counter.value);
    const add = () => {
        store.dispatch(increment())
    }
    const add100 = () => {
        store.dispatch(incrementByAmount(100))
    }
    useEffect(() => {
        const unsubscribe = store.subscribe(() => {
            setState(store.getState().counter.value);
        });
        return () => unsubscribe();
    }, []);
    return(
        <div>
            <h3>RtkPage</h3>
            <p>{state}</p>
            <button onClick={add}>add</button>
            <button onClick={add100}>add100</button>
            <button onClick={()=>store.dispatch({type:"counter/increment"})}>add</button>
        </div>
    )
}

注意 我们可以使用react-redux简化这里,具体看上一篇文章

接下来让我们看看怎么实现一个rtk

  1. configureStore

接收{reducer},创建状态仓库,return 一个 store。

还记得我们之前实现了redux中的createStore和combineReducers吗?juejin.cn/post/753167...

js 复制代码
export function configureStore({reducer}){
    const rootReducer = combineReducers(reducer)
    const store = createStore(rootReducer)
    return store
}

那么我们很容易就建立了一个状态仓库。

  1. createSlice

接收{name,initialState,reducers},返回{name,reducer,actions}

(1)name不用做任何修改,直接传出来就行

(2)actions 要注意 incrementByAmount:(state,action)=>{ state.value += action.payload }这种用法,我们要获取type和payload(args[0])。

(3)reducers本身不麻烦,但是要注意rtk内置了immer,不是标准的reducer,我们目前可以先使用rtk的createReducer函数。

js 复制代码
    import {createReducer} from '@reduxjs/toolkit'
    export function createSlice({name,initialState,reducers}){
    const reducerNames = Object.keys(reducers)
    const actionCreators = {}
    const sliceCaseReducerByType = {}
    reducerNames.forEach(reducerName=>{
        const r = reducers[reducerName]
        const type = `${name}/${reducerName}`
        sliceCaseReducerByType[type] = r
        actionCreators[reducerName] = createAction(type)
    })
    let _reducer
    function buildReducer(){
    return createReducer(initialState,(builder)=>{
        for(let key in sliceCaseReducerByType)
        builder.addCase(key,sliceCaseReducerByType[key])
    })
}
    return{
        name, 
        actions:actionCreators,
        reducer: (state,action)=>{
            if(!_reducer){
                _reducer = buildReducer()
            }
            return _reducer(state,action)
        }
    }
}

function createAction(type){ //把接收到的参数转化成payload,type给dispatch调用
    function creator(...args){
        return {
            type,
            payload: args[0]
        }
    }
    creator.type = type
    return creator
}
  1. createReducer

接收nitialState和一个Callback,返回一个reducer,这个步骤是把虚假的reducer转化为真正的reducer。immer中的produce函数就是把它变成真正的reducer。

js 复制代码
import {produce} from "immer"
function createReducer(initialState,mapOrBuilderCallback){
    let [actionMap] = executeReducerBuilderCallback(mapOrBuilderCallback)
    // actionMap就是 counter/increment: reducer .....
    function reducer(state = initialState,action){
        const caseReducers = [actionMap[action.type]]
        return caseReducers.reduce((previousState,caseReducer)=>{
            if(caseReducer){
                return produce(previousState,(draft)=>{
                    return caseReducer(draft,action)
                })
            }
            return previousState
        },state)
    }
    return reducer
    }
    function executeReducerBuilderCallback(mapOrBuilderCallback){
        const actionsMap = {};
        const builder = {
            addCase: (type, reducer) => {
            actionsMap[type] = reducer;
            return builder;
            },
        };
        mapOrBuilderCallback(builder);
        return [actionsMap];
}

至此我们就写完了rtk。

待拓展:immer

相关推荐
想要学好前端的阿毛19 小时前
React状态管理库 - react-redux篇
redux
土豆12509 天前
RTK Query 完全指南:简化数据获取与状态管理
redux
潘小安9 天前
三伏天,学点react-redux 源码降降火
react.js·源码·redux
止观止12 天前
Redux架构解析:状态管理的核心原理
前端·react.js·架构·redux
_一两风13 天前
深入理解 Reducer:从纯函数到 useReducer 的实践
javascript·react.js·redux
Spider_Man14 天前
React组件通信与Redux状态管理完全指南
前端·javascript·redux
HarderCoder2 个月前
ByAI:Redux中间件的原理和ts简化实现
前端·redux
HarderCoder2 个月前
ByAI:Redux及中间件原理和实现
redux
市民中心的蟋蟀2 个月前
第九章 案例 3 - Valtio 【上】
前端·react.js·redux