博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
redux原理
阅读量:4677 次
发布时间:2019-06-09

本文共 5173 字,大约阅读时间需要 17 分钟。

Redux实现原理

不同组件需要依赖同一个数据的时候,就需要状态提升至这些组件的根组件。

redux是状态统一管理工具,需要使用它的原因是: 组件之间通信统一管理,方便代码维护。

React中有一个特性context,只要某个组件使用context存储了数据,那么这个组件的所有子组件都可以访问该context内容,并且还可以修改它。就像是这个组件的全局变量,它的所有子组件都可以访问这个全局变量。

如下图,假设要更改主题颜色,那么在Index根组件的context中存储当前主题色,那么它的子组件header,footer,title,menu都可以访问到,并且可以修改。
1332769-20180522113744539-1141962164.png

Redux的统一数据管理,与React的关联之处利用的就是context特性

但是context有一个缺点就是,所有的子组件都可以修改共享的内容,每个组件都能够改 context 里面的内容会导致程序的运行不可预料。所以React团队的做法就是,提高修改的门槛,修改数据时统一调用dispatch函数,并且需要传入修改类型,如果dispatch中不存在该类型,则不允许修改。
接下来简单推理一下redux的实现过程(假设有组件Index,Header,Footer)。
1、第一步是需要有一个存储数据的对象,定义为appState

var appState = {        themeColor:'red',        themeBackground:'black'    };    //还需要一个修改数据的函数    function dispatch(action){        switch(action.type){            case 'UPDATE_THEME_COLOR':                appState.themeColor = action.color;break;            case 'UPDATE_THEME_BACKGROUND':                appState.themeBackground = action.color;break;            default break;              }    }    //修改完数据,就需要重新渲染了,定义渲染函数    function renderApp(state){        renderHeader(state);        renderFooter(state);    }    function renderHeader(state){        header = document.getElementById('header');        header.style.color = state.color;        header.style.backgroundColor = state.themeBackground;    }    function renderFooter(state){        title = document.getElementById('footer');        footer.style.color = state.color;        footer.style.backgroundColor = state.themeBackground;    }        dispatch({type:'UPDATE_THEME_COLOR',color:'green'})//修改主题色    renderApp(appState)//执行重新渲染

2、封装state和dispatch,命名为store,方便复用,同时添加监听,当数据变化时,通知订阅者重新渲染

function createStore(state,stateChanger){        const getState = () => state;//获取数据        const listeners = [];        const subscribe = (listener) => listeners.push(listener);        const dispatch = (action) => {            stateChanger(state, action);            listeners.forEach((listener)=>listener());        };        return {getState,dispatch,subscribe};    }    //实例化一个store。为了统一命名,dispatch改为stateChanger,appState改名为state    const store = createStore(state,stateChanger);    renderApp(store.getState());//首次渲染    store.subscribe(renderApp(store.getState()));//添加订阅者,监听到变化就重新渲染数据    store.dispatch({type:'UPDATE_THEME_COLOR',color:'green'});//修改主题

3、第二步有一个很大的缺陷就是,每次修改数据就重新全部渲染一遍,对性能影响很大。

优化点是: 判断数据是否有变化,如果没变化就不需要重新渲染,另外stateChanger与state合为一体。

//此处用到es6的浅复制,例如    let a = { name:'HAPPY',attr:{age:23},common:{sex:'女'}};    let b = {...a,attr:{age:24}};//b为{name:'HAPPY',attr:{age:24},common:{sex:'女'}}     a.name===b.name//true    a.attr===b.attr//false    a.common===b.common//true    //这样有50%以上的复用率    function stateChanger(state,action){        if(!state){             return {                 themeColor:'red',                 themeBackground:'black'             }        }        const newState = {...state};        switch(action.type){            case 'UPDATE_THEME_COLOR':                return {                    ...newState,                    themeColor: action.color                };            case 'UPDATE_THEME_BACKGROUND':                return {                    ...newState,                    themeBackground: action.color                };            default                 return newState;            }    }    //那么渲染的时候需要知道oldState和newState,这样才能对比数据的变化    function renderApp(state,oldState={}){//此处oldState放在后面,并且给默认值,是为了兼容首次渲染,首次渲染olsState是没有值的,所以给默认值        if(oldState===state){            return;        }        renderHeader(oldState,state);        renderFooter(oldState,state);    }    //如果renderHeder需要的渲染的数据是state内的子对象,那么在renderHeader渲染之前,也需要判断一下数据是否有变化,此处举的例子state结构简单,所以不需要判断。        function createStore(stateChanger){//此处是优化state与stateChanger结合。        let state = null        const getState = () => state;//获取数据        const listeners = [];        const subscribe = (listener) => listeners.push(listener);        const dispatch = (action) => {            state = stateChanger(state, action);            listeners.forEach((listener)=>listener());        };                dispatch({});//初始化,获取state        return {getState,dispatch,subscribe};    }    //最后需要oldState,那么我们就需要定义oldState    const store = createStore(stateStranger);    const oldState = store.getState();    store.subscribe(()=>{        const newState = store.getState();        renderApp(oldState,newState);        oldState = newState;    });//添加监听    renderApp(store.getState())//首次渲染    store.dispatch({type:'UPDATE_THEME_COLOR',color:'green'});//修改主题

4.此时的stateChanger是一个纯函数,就是内部逻辑只与参数有关,并且无副作用(也就是对其他数据没有任何影响)。它要做的仅仅是 —— 初始化和计算新的 state。(并不会修改state,因为我们每次返回的都是新的对象)

而这个函数就是redux中的reducer,那么我们给stateChanger改名字为reducer.现在我们的redux就实现完成了。

function reducer(state,action){...}     function createStore(reducer){...}     //接下来我们就可以定义不同的reducer,生成不同的store了,并且修改监听,例如     function themeReducer(state,action){...}     const store = createStore(themeReducer);     // 监听数据变化重新渲染页面     store.subscribe(() => renderApp(store.getState()))     // 首次渲染页面     renderApp(store.getState())     // 后面可以随意 dispatch 了,页面自动更新     store.dispatch(...)
但是我们怎么跟react进行连接呢?怎么把redux用在react中呢?就需要react-redux来连接。下一篇继续

参考教程:()

转载于:https://www.cnblogs.com/HappyYawen/p/9071238.html

你可能感兴趣的文章
单元测试之初识
查看>>
golang github.com/go-sql-driver/mysql 遇到的数据库,设置库设计不合理的解决方法
查看>>
内存分配 保存数据
查看>>
嵌入式实时操作系统的可裁剪性及其实现
查看>>
VC++2012编程演练数据结构《31》狄杰斯特拉算法
查看>>
盘点:移动服务 #AzureChat
查看>>
Sass学习笔记
查看>>
C语言练习
查看>>
Eclipse:An internal error occurred during: "Building workspace". GC overhead limit exceeded
查看>>
纯Css实现Div高度根据自适应宽度(百分比)调整
查看>>
jboss eap6.1(4)(部署应用)
查看>>
配置jboss EAP 6.4 数据库连接超时时间
查看>>
【BZOJ5005】乒乓游戏 [线段树][并查集]
查看>>
前端页面数据埋点、分析和参考
查看>>
NBear简介与使用图解
查看>>
ng-app一些使用
查看>>
sql 查询目标数据库中所有的表以其关键信息
查看>>
C# 高效率创建字符串类(StringBuilder)
查看>>
sql server 符号函数sign
查看>>
bzoj 4337 树的同构
查看>>