Redux实现原理

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

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

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

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

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来连接。下一篇继续

参考教程:(http://huziketang.mangojuice.top/books/react)

redux原理的更多相关文章

  1. 轻松理解Redux原理及工作流程

    轻松理解Redux原理及工作流程 Redux由Dan Abramov在2015年创建的科技术语.是受2014年Facebook的Flux架构以及函数式编程语言Elm启发.很快,Redux因其简单易学体 ...

  2. [转载]Redux原理(一):Store实现分析

    写在前面 写React也有段时间了,一直也是用Redux管理数据流,最近正好有时间分析下源码,一方面希望对Redux有一些理论上的认识:另一方面也学习下框架编程的思维方式. Redux如何管理stat ...

  3. Redux原理(一):Store实现分析

    写在前面 写React也有段时间了,一直也是用Redux管理数据流,最近正好有时间分析下源码,一方面希望对Redux有一些理论上的认识:另一方面也学习下框架编程的思维方式. Redux如何管理stat ...

  4. 解析:让你弄懂redux原理

    作者: HerryLo 本文永久有效链接: https://github.com/AttemptWeb...... Redux是JavaScript状态容器,提供可预测化的状态管理. 在实际开发中,常 ...

  5. Redux 原理和简单实现

    前端开发中React + Redux 是大部分项目的标配,Redux也是我喜欢的库之一,他的源码也拜读过几遍,每次都有很多收获,尤其他的中间件设计模式,对自己封装一些库提供了思想上的指导. Redux ...

  6. react-redux原理分析

    写在前面 之前写了一篇分析Redux中Store实现的文章(详见:Redux原理(一):Store实现分析),突然意识到,其实React与Redux并没有什么直接的联系.Redux作为一个通用模块,主 ...

  7. React + Redux 入坑指南

    Redux 原理 1. 单一数据源 all states ==>Store 随着组件的复杂度上升(包括交互逻辑和业务逻辑),数据来源逐渐混乱,导致组件内部数据调用十分复杂,会产生数据冗余或者混用 ...

  8. react-redux原理

    react-redux原理分析 写在前面 之前写了一篇分析Redux中Store实现的文章(详见:Redux原理(一):Store实现分析),突然意识到,其实React与Redux并没有什么直接的联系 ...

  9. 对redux的理解

     redux原理 某公司有物流(actionType).电商(actionType).广告(actionType)3块业务,在公司财务系统(state)统一记录着三块业务分别赚取到的资金.某天,电商业 ...

随机推荐

  1. nutz 自定义sql的使用

    虽然提供了Cnd,但是用起来是觉得有点不方便,然后就直接编写Sql语句.nutz提供了一些方法. Nutz.Dao 的自定义 SQL 部分的解决方案是: // 不推荐使用 用户可以硬编码 SQL 语句 ...

  2. RxSwiftライブラリの作り方 〜Observer/Observable編〜

    RxSwiftライブラリの作り方をご紹介します.一つの記事ですべてを説明するのは非常に厳しいので.まず Observer や Observable といった基本的なコンポーネントとその周辺について.ひ ...

  3. Arguments Optional FreeCodeCamp

    function add() { if(typeof arguments[0] !== "number" || (arguments.length > 1 && ...

  4. poj 3669 bfs(这道题隐藏着一个大坑)

    题意 在x,y坐标系,有流星会落下来,给出每颗流星落下来的坐标和时间,问你能否从(0,0)这个点到一个安全的位置.所谓的安全位置就是不会有流星落下的位置. 题解: 广搜,但是这里有一个深坑,就是搜索的 ...

  5. The socket is closed!

    关闭mongodb    /usr/local/app/mongidb//bin/mongod   --shutdown  --dbpath /usr/local/data/mongo/data/ 然 ...

  6. 《Exception》第八次团队作业:Alpha冲刺

    一.项目基本介绍 项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 作业链接地址 团队名称 Exception 作业学习目标 1.掌握软件测试基础技术.2.学习迭代式增量软 ...

  7. 51nod-完美字符串(贪心)

    约翰认为字符串的完美度等于它里面所有字母的完美度之和.每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数. 约翰不在乎字母大小写.(也就是说字母F和f)的完美度相同. ...

  8. BZOJ 3434 [WC2014]时空穿梭 (莫比乌斯反演)

    题面:BZOJ传送门 洛谷传送门 好难啊..反演的终极题目 首先,本题的突破口在于直线的性质.不论是几维的空间,两点一定能确定一条直线 选取两个点作为最左下和最右上的点! 假设现在是二维空间,选取了$ ...

  9. 06006_redis数据存储类型——String

    1.概述 (1)字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这意味着该类型可以接受任何格式的数据,如JPEG图像数据或Json对象描述信息等: (2)在Redis中 ...

  10. Java并发之线程间的同步协作与通信协作

    1,Monitor监视器与syncrhoized实现原理 1.1:Monitor Monitor是一个同步工具,相当于操作系统中的互斥量(mutex),即值为1的信号量. 它内置与每一个Object对 ...