作为react的粉丝,当然要吐槽一下react组件通信问题。react的单向数据流是组件通信的一大阻碍,只允许父组件向子组件传值,子组件向父组件传值只能通过父组件向子组件传递回调函数实现。如果在深层次的组件结构当中,复杂与繁多的回调会大大增加程序的维护难度与可读性,延长开发周期。即使react实现的再优秀,组件通信没处理好,还是一坨屎。redux给react的组件通信带来解决方案:构建一个大的状态作用域(一个大组件),大组件里的所有组件状态变化都只需要维护大组件,更新的状态都有大组件开始下发,这样就避免了子组件向父组件传值需要回调方法的问题。

redux优点:贯彻了react的单向数据流思想,避免父子组件通信时繁琐的回调,清晰的数据流简化了业务逻辑实现,提高应用维护效率。

redux槽点:为了数据中心化与自动化测试分离出了action与redcuer与mapStateToProps,简单的数据操作被复杂化了。每次dispatch都会重新渲染状态作用域里的所有组件,虽然react使用diff算法筛选出需要改变的节点进行渲染(优化了性能),但是在庞大以及深层次的组件结构中,diff带来的消耗还是不可忽视的。

  我格外厌恶redux繁琐的操作,所以自己实现了一个简化版的redux。把action与redcuer合并、废弃了mapStateToProps简化了redux的数据操作。由于action与redcuer的合并后存在数据依赖,所以合并后的action不能做数据自动化测试。除了简化redux的繁琐的数据操作之外,还通过监听组件里的动态数据与dispatch更新的数据对比检测该组件是否需要重新渲染,解决redux最大的弊端【redux组件渲染弊端:redux dispatch后没有变化的组件也会被重新渲染,这是不必要的性能消耗】。我还丰富了Component基类给每个组件提供了重新渲染检测功能。

redux-simple.s实现如下:

 import React,{Component,createElement} from "react";
var event=function(){
var propsment={};
var dispatchProps={};
return {
//添加监听属性
listenProps:function(props,_this){
if(_this.constructor&&_this.constructor.name){
propsment[_this.constructor.name]=props;
}else{
throw new Error("监听对象不是react组件");
}
},
//清空监听的属性
emptyProps:function(){
propsment={};
},
//检测是否需要更新
checkProps:function(_this){
var data=propsment[_this._reactInternalInstance.getName()]||[];
var propKeys=Object.keys(dispatchProps);
//没有监听属性的组件直接更新
if(!data.length){
return true;
}
for(var i=0;i<data.length;i++){
//判断监听的属性是否存在于更新数据里面,存在则更新组件
if(propKeys.indexOf(data[i])!=-1){
return true;
}
}
return false;
},
//监听更新的数据
listenDispatch:function(props){
dispatchProps=props;
}
} }()
export function connect(App,actions){
let dispatch,getState;
dispatch=getState=function(){
throw new Error("组件还没初始化");
}
class Main extends Component{
constructor(props){
super(props);
this.constructor.setState=dispatch=(data)=>{
//监听更新的数据
event.listenDispatch(data);
//更新store
this.setState(Object.assign({},this.state,data));
}
getState=()=>{
return Object.assign({},this.state);
}
this.actions=bindAction(actions,dispatch,getState||{});
}
render(){
return <div>
{createElement(App,Object.assign({dispatch:dispatch,listenProps:event.listenProps,getState:getState,actions:this.actions},this.props,this.state))}
</div>
}
}
return Main;
}
//action方法绑定dispatch并支持异步
function bindActionCreators(action,dispatch,getState){
if(typeof action==="function"){
return function(){
[].unshift.call(arguments,getState());
var newState=action.apply(null,arguments);
if(typeof newState==="function"){
newState(dispatch)
}else if(isObject(newState)){
dispatch(newState);
}else{
throw new Error("action方法返回值只能是函数或者对象");
}
}
}
}
//给所有的action方法绑定dispatch
export function bindAction(actions,dispatch,getState){
var newActions={};
if(isObject(actions)){
var keys=Object.keys(actions);
keys.forEach(function(value){
newActions[value]=bindActionCreators(actions[value],dispatch,getState)
})
return newActions;
}else if(actions){
throw new Error("actions必须是对象")
}
}
//检测是否是一个对象
let isObject=(data)=>{
if(Object.prototype.toString.call(data)=="[object Object]"){
return true;
}else{
return false;
}
}
//构建新的组件基类
export default class NewCom extends Component{
shouldComponentUpdate(nextProps){
return event.checkProps(this,nextProps); //检测是否重新渲染该组件
}
componentWillUnmount(){
event.emptyrProps(); //清空监听列表
}
}

使用实例如下:

  

 import ReactDom from "react-dom";
import React from "react";
import Component,{connect} from "./react-extend.js";
import * as actions from "./action/test.js";
class Test01 extends Component{
constructor(props){
super(props);
this.props.listenProps(["test01"],this); //监听该组件的动态数据
}
render(){
return <h1>{this.props.test01}</h1>
}
}
class Test02 extends Component{
constructor(props){
super(props);
this.props.listenProps(["test02"],this); //监听该组件的动态数据
}
clickHandler(){
this.props.actions.changeTest01(789);
}
render(){
return <h1 onClick={this.clickHandler.bind(this)}>{this.props.test02}</h1>
}
}
class Main extends Component{
componentDidMount(){
this.props.actions.init({
test01:123,
test02:456,
})
}
render(){
return <div>
<Test01 {...this.props}/>
<Test02 {...this.props}/>
</div>
}
}
var NewMain=connect(Main,actions);
ReactDom.render(
<NewMain />,
document.getElementById("container")
)

action:

 export function changeTest01(state,value){
return {
test01:value,
}
}
export function init(state,obj){
return obj;
}

redux-simple 简化版的redux的更多相关文章

  1. redux源码解析-redux的架构

    redux很小的一个框架,是从flux演变过来的,尽管只有775行,但是它的功能很重要.react要应用于生成环境必须要用flux或者redux,redux是flux的进化产物,优于flux. 而且r ...

  2. react第十六单元(redux的认识,redux相关api的掌握)

    第十六单元(redux的认识,redux相关api的掌握) #课程目标 掌握组件化框架实现组件之间传参的几种方式,并了解两个没有任何关系组件之间通信的通点 了解为了解决上述通点诞生的flux架构 了解 ...

  3. [Redux + Webpack] Hot reloading Redux Reducers with Webpack

    Webpack will hot reload the component, but the reducer we need hard refresh. To sovle the problem, g ...

  4. Redux学习笔记:Redux简易开发步骤

    该文章不介绍Redux基础,也不解释各种乱乱的概念,网上一搜一大堆.只讲使用Redux开发一个功能的步骤,希望可以类我的小白们,拜托它众多概念的毒害,大牛请绕道! 本文实例源代码参考:React-Re ...

  5. redux sample with slim redux source code

    code sample没有package.json文件,也就没有任何外部依赖,直接使用slim redux source code. slim resux只有90多行. nodejs对es6的impo ...

  6. [Redux] Important things in Redux

    Root Smart component can be overloaded, divide 'smart' component wisely & using Provider. Proble ...

  7. 1.Redux学习1,Redux

    Redux流程图如上: Action就是一条命令 Store顾名思义就是存储数据的, Reducers是一个回调函数用于处理数据,它处理完数据会返回给Store存储起来 基本流程就是:组件中用Stor ...

  8. 4 react 简书 引入 redux 的 combineReducers 对 redux 数据进行管理

    1. src 下的 common 下的 header 创建 store 文件夹 下创建 reducer.js # src/common/header/store/reducer.js const st ...

  9. React之redux学习日志(redux/react-redux/redux-saga)

    redux官方中文文档:https://www.redux.org.cn/docs/introduction/CoreConcepts.html react-redux Dome:https://co ...

随机推荐

  1. Fetcher类的工作流程

    Fetcher类工作流程: FileInputFormat.addInputPath(job, new Path(segment, CrawlDatum.GENERATE_DIR_NAME)); jo ...

  2. Gold Balanced Lineup

    #include<cstdio> #include<cstring> #include<cmath> #include <cstdlib> #defin ...

  3. 用UNetbootin来安装USB LINUX,好像比ULTRA ISO省事

    UNetbootin can create a bootable Live USB drive, or it can make a "frugal install" on your ...

  4. Delphi GDI或图像处理的博客

    http://blog.csdn.net/w1028489713/article/category/1918251

  5. POJ1836 Alignment(LIS)

    题目链接. 分析: 从左向右求一遍LIS,再从右向左求一遍LIS,最后一综合,就OK了. 注意: 有一种特殊情况(详见discuss): 8 3 4 5 1 2 5 4 3 答案是:2 AC代码如下: ...

  6. 设计模式(三): FACTORY工厂模式 -- 创建型模式

    1.定义 定义一个用于创建对象的接口,让子类决定实例化哪一个类,Factory Method使一个类的实例化延迟到了子类. 2.适用场景 1.第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体 ...

  7. 【转】设置TextView文字居中

    原文网址:http://blog.csdn.net/lanpy88/article/details/6616924 有2种方法可以设置TextView文字居中: 一:在xml文件设置:android: ...

  8. 【转】android 4.3 BLE onCharacteristicWrite没有回调

    原文网址:http://bbs.csdn.net/topics/390882717?page=1 问题1.我在自己程序有开一个Timer定时去readCharacteristic, 每次read可以成 ...

  9. 挂载nfs系统问题之: Root-NFS: Server returned error -13 while mounting

    今天换了个路由器,由于是自动分的IP,现在的IP和之前的不在同一网段.以前是192.168.0.xxx,现在是192.168.1.xxx.本以为将serverip,ipaddr,bootargs这些参 ...

  10. UVa 10025: The ? 1 ? 2 ? ... ? n = k problem

    这道题仔细思考后就可以得到比较快捷的解法,只要求出满足n*(n+1)/2 >= |k| ,且n*(n+1)/2-k为偶数的n就可以了.注意n==0时需要特殊判断. 我的解题代码如下: #incl ...