首页 > 其他分享 >Redux 及Redux-Toolkit 使用笔记及简易实现

Redux 及Redux-Toolkit 使用笔记及简易实现

时间:2024-08-06 16:51:04浏览次数:14  
标签:const reducer Toolkit 笔记 state return Redux store reducers

Redux 及Redux-Toolkit 使用笔记及简易实现

依赖的包 npm install @reduxjs/toolkit react-redux

创建Store并且将它注入到app中。

  • 一般使用configureStore({reducers:{}}),这种方式,我们可以在各个模块里面定义各自的reducer,然后在store里面使用它。这个方法返回的就是store的实例,它里面有store:{dispatch:Function,getState:Function}等方法,整个app对于store的API调用,都得靠这个对象。
  • 我们也可以在hook函数中来使用store,在App的顶层,我们使用import {Provider} from 'react-redux';<Provider store={storeinstance}></Provider>.这样我们就可以在全局使用useSelector(selector:Func,options?:EqualFunc)的方式来对于store进行引用。
  • 我们也可以将store里面的slice 通过组件的参数来传递到组件。可以使用function connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?),用法其实是一种HOC的写法,export MyComponnet = connect()(InnerComponent)

Store可以看成是整个数据库,里面得需要各自不同的表,所以,我们有了Slice的概念。

  • toolkit里面提供了const slice = createSlice(opts:{name:string,initializeValue:any,reducers:{}})。先来看看它返回的slice对象.最重要的两个是reducer,actions.其中reducer我们得把它交给configureStore,而它的actions,我们可以结合dispatch来使用dispatch(someAction(payload))
export interface Slice<State = any, CaseReducers extends SliceCaseReducers<State> = SliceCaseReducers<State>, Name extends string = string> {
    /**
     * The slice name.
     */
    name: Name;
    /**
     * The slice's reducer.
     */
    reducer: Reducer<State>;
    /**
     * Action creators for the types of actions that are handled by the slice
     * reducer.
     */
    actions: CaseReducerActions<CaseReducers>;
    /**
     * The individual case reducer functions that were passed in the `reducers` parameter.
     * This enables reuse and testing if they were defined inline when calling `createSlice`.
     */
    caseReducers: SliceDefinedCaseReducers<CaseReducers>;
    /**
     * Provides access to the initial state value given to the slice.
     * If a lazy state initializer was provided, it will be called and a fresh value returned.
     */
    getInitialState: () => State;
}
  • 那如何读取slice里面的数据,我们可以通过const readSlice = createSelector(sliceselector1,sliceSelector2,...,joinResultFunc),这个API或者通过useSelector(sliceSelector)。这两种有什么区别
    • createSelector是API调用,所以不要放到FC里面,它其实是提高了一个缓存的方式。如果所以的依赖项返回的值的引用都没有变化,那么readSlice(state),其实是不会执行的,返回的值还是上次的值,跟React.memo()有点类似。
    • useSelector()这个是hook函数,当state里面的状态变化了,这个hook一定会被执行,如果返回的值发生了变化,那么,组件会刷新。所以,如果将createSelector返回的值,传递给useSelector,那么就起到了一个缓存的作用。如果State发生变化,但是我们关注的slice没有发生变化,那当前组件是不会刷新的。还要注意的是每次组件render的时候,useSelector()里面的函数都会执行,如果返回的值没有变化,则返回值不变。所以使用createSelect的返回值,起到了一种优化的作用。
  • 还要一个关键,createSlice里面的reducers应该怎么写?
    它其实就是一个{[key:string]:(previousState,action)=>newState|void}。这个createSlice内部使用了immerjs来帮助我们做优化,所以,如果我们之间对原始的对象做了修改,它内部会将它转变成新的对象。

最后一个问题能否实现一个简单的实现

  • createSlice的简易实现
function createSlice(opts:{name:string,reducer:{[k in string]:(previous:any,action:{type:string})=>any},initialValue}){
    const {name,reducer,initialValue}=opts;
    const [actions,reducers]=[{},{}];
    let result={name,initialValue,actions,reducers};
    const getSliceData=(state)=>state[name];
    for(let [actionName,reduceFunc] of Object.entries(reducer)){
        const actionFunc=(payload:any)=>{
            return {
                type:`${name}-${actionName}`,
                payload,
            }
        };

        const reducer=(previous:any,action:{type:string,payload:any})=>{
             return reduceFunc(getSliceData(previous),action);
        }
        Object.assign(actions,{[actionName]:actionFunc});
        Object.assign(reducers,{[actionName]:reducer})
    }

    return result;
}

  • useSelector(selectFunc)的简易实现
function useSelector(selectFunc){
    const store = useStore();
    const sliceData= React.useMemo(()=>{
        return selectFunc(store)
    },[store]);
    return sliceData;
}

  • createSelector(...dependencies,joint)的简易实现
function createSelector(selectFunc){
    const dependencies=arguments||[].slice(0,arguments.length-1);
    const joint=arguments[arguments.length-1]
    return function(state,...remainging){
        const dependencyValues = dependencies.map(it=>it(state,...remainging));
        return React.useMemo(()=>{
          return joint(dependencyValues,...remainging);
        },dependencyValues)
    }
}
  • ConfigureStore(opts)的简单实现
function configStore(opts:{reducers,}){
    const {reducers}=opts;
    let _innerDipatch:Function|null;
    let _state:any;
    const dispatch=(action)=>{
          _innerDipatch(action);
    }
    const getState=()=>{
         return _state;
    }
    const setDispatch=(dispatchFunc)=>{
        _innerDipatch=dispatchFunc;
    };
    const updateStore=(state)=>{
        _state=state;
    }

    const reducersWrapper=(previousState,action)=>{
        const {type,payload}=action;
        return reducers[type](previousState,payload);
    }
    
    return {dispatch,getState,reducersWrapper,setDispatch,updateStore}
}


const ReduxContext=React.createContext({store:{},dispatch:()=>{}});

function useStore(){
    return React.useContext(ReduxContext).store;
}

function useDipatch(){
    return React.useContext(ReduxContext).dispatch;
}


function ReduxProvider(props:{store:any,children:any}){
    const {store}=props;
    const [state,dispatch]=React.useReducer(store.reducersWrapper,{});
    React.useEffect(()=>{
        store.setDispatch(dispatch);
        store.updateStore(state);
    },[store,state]);
    
    return (
        <ReduxContext.Provider value={{state,dispatch}}>
            {children}
        </ReduxContext.Provider>
    )
}

标签:const,reducer,Toolkit,笔记,state,return,Redux,store,reducers
From: https://www.cnblogs.com/kongshu-612/p/18345550

相关文章

  • C:指针学习(1)-学习笔记
    目录前言:知识回顾:1、const1.1const修饰普通变量1.2 const修饰指针变量1.3总结:2、指针运算2.1指针+-整数2.2指针-指针2.3指针的关系运算3、指针的使用结语:前言:距离上一次更新关于初识指针的内容已经有一段时间了,本文旨在继续深入探讨指针的相关知识。在......
  • Obsidian学习笔记-界面图标介绍
    背景打开Obsidian,会看到界面是极简画风,初学者或许难以弄清界面边框上诸多小图标的含义,本文将详细介绍Obsidian界面上共27个图标,并逐一列图展示其功能和使用效果。并根据的 Obsidian页面设计从左到右,分为功能页(左)、内容页、功能页(右)三大板块依次介绍。一、功能页(左)这......
  • C语言学习笔记 Day9(指针--上)
    Day9 内容梳理:目录Chapter7  指针7.0内存的概述7.1 基础知识(指针&指针变量)7.2指针7.3指针变量(1)野指针(2)空指针(3)万能指针void*(4)const修饰的指针变量Chapter7  指针7.0内存的概述存储器:计算机中用来存储程序和数据以便辅助CPU进行运算处理的组件......
  • 网络安全学习路线+自学笔记(超详细) 自学网络安全看这一篇就够了
    一、什么是网络安全网络安全是一种综合性的概念,涵盖了保护计算机系统、网络基础设施和数据免受未经授权的访问、攻击、损害或盗窃的一系列措施和技术。经常听到的“红队”、“渗透测试”等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。作为一......
  • 笔记本CPU天梯图(2024年8月),含AMD/骁龙等新CPU
    原文地址(高清无水印原图/持续更新/含榜单出处链接):2024年8月笔记本CPU天梯图2024年8月笔记本CPU天梯图2024年8月5日更新日志:常规更新CinebenchR23、PassMark笔记本CPU天梯图,新增Geekbench6.2单核多核天梯图(Notebookcheck);移除鲁大师天梯图。----------手动分割线------......
  • Living-Dream 系列笔记 第75期
    CF126B朴素解法:求出原字符串的最长border,并kmp匹配出出现在中间的最长border,若没有则不断缩短border的长度,直到中间存在。若border长度减到了\(0\),则无解。我们通过画图来探索优化方式。如图,蓝色部分为原串的最长border,红色部分为蓝色部分的最长border。容易发现,......
  • C++学习笔记----Strings与String View(4)-- 字符串操作
        今天讲点简单易懂的,字符串操作,当然了,不是全部,列出几个典型的字符串操作,完整地可以参考相关资料,网上一搜一把哦。substr(pos,len):返回特定位置pos,特定长度的子字符串。find(str):返回字符串的位置,如未找到则返回string::npos。replace(pos,len,str):用新的字符串str......
  • C++学习笔记----Strings与String View(5)-- 字符串文本
    今天我们继续来学习C++的string:1、字符串文本    字符串文本通常会被解析成字符指针常量(constchar*)或者字符数组常量(constchar[]),如果想要达到声名std::string常量的目的,则需要在声明时在常量字符串后加一个s,示例如下: autostring1{"HelloWorld"}; //string1为......
  • 【笔记】矩阵
    1Template1.1轻量化灵活度较高,适合直接调用矩阵内值的情形。typedefvector<vector<int>>Matrix;voidresize(Matrix&a,intn,intm){ a.resize(n,vector<int>(m));}Matrixoperator*(constMatrix&a,constMatrix&b){ Matrixres;resize(re......
  • java笔记5
    9.抽象类与接口抽象类抽象类的概念抽象类是面向对象编程中不能被实例化的一种类,它通常被用作基类,为其他类提供公共的接口或实现。什么是抽象抽象是将现实世界中的复杂事物简化为基本特征的过程,它关注对象的本质特征,忽略细节,只说明做什么,不说明怎么做。为什么要抽象抽象帮......