zoukankan      html  css  js  c++  java
  • redux-simple 简化版的redux

      作为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实现如下:

      1 import React,{Component,createElement} from "react";
      2 var event=function(){
      3     var propsment={};
      4     var dispatchProps={};
      5     return {
      6         //添加监听属性
      7         listenProps:function(props,_this){
      8               9             if(_this.constructor&&_this.constructor.name){
     10                 propsment[_this.constructor.name]=props;
     11             }else{
     12                 throw new Error("监听对象不是react组件");
     13             }
     14         },
     15         //清空监听的属性
     16         emptyProps:function(){
     17             propsment={};
     18         },
     19         //检测是否需要更新
     20         checkProps:function(_this){
     21             var data=propsment[_this._reactInternalInstance.getName()]||[];
     22             var propKeys=Object.keys(dispatchProps);
     23             //没有监听属性的组件直接更新
     24             if(!data.length){
     25                 return true;
     26             }
     27             for(var i=0;i<data.length;i++){
     28                 //判断监听的属性是否存在于更新数据里面,存在则更新组件
     29                 if(propKeys.indexOf(data[i])!=-1){
     30                     return true;
     31                 }
     32             }
     33             return false;
     34         },
     35         //监听更新的数据
     36         listenDispatch:function(props){
     37             dispatchProps=props;
     38         }
     39     }
     40     
     41     
     42 }()
     43 export function connect(App,actions){
     44     let dispatch,getState; 
     45     dispatch=getState=function(){
     46         throw new Error("组件还没初始化");
     47     }
     48     class Main extends Component{
     49         constructor(props){
     50             super(props);
     51             this.constructor.setState=dispatch=(data)=>{
     52                 //监听更新的数据
     53                 event.listenDispatch(data);
     54                 //更新store
     55                 this.setState(Object.assign({},this.state,data));
     56             } 
     57             getState=()=>{
     58                 return Object.assign({},this.state);
     59             }
     60             this.actions=bindAction(actions,dispatch,getState||{});
     61         }
     62         render(){
     63             return <div>
     64                 {createElement(App,Object.assign({dispatch:dispatch,listenProps:event.listenProps,getState:getState,actions:this.actions},this.props,this.state))}
     65             </div>
     66         }
     67     }
     68 return Main;
     69 }
     70 //action方法绑定dispatch并支持异步
     71 function bindActionCreators(action,dispatch,getState){
     72     if(typeof action==="function"){
     73         return function(){
     74             [].unshift.call(arguments,getState());
     75             var newState=action.apply(null,arguments);
     76             if(typeof newState==="function"){
     77                 newState(dispatch)
     78             }else if(isObject(newState)){
     79                 dispatch(newState);
     80             }else{
     81                 throw new Error("action方法返回值只能是函数或者对象");
     82             }
     83         }
     84     }
     85 }
     86 //给所有的action方法绑定dispatch
     87 export function bindAction(actions,dispatch,getState){
     88     var newActions={};
     89     if(isObject(actions)){
     90         var keys=Object.keys(actions);
     91         keys.forEach(function(value){
     92             newActions[value]=bindActionCreators(actions[value],dispatch,getState)
     93         })
     94         return newActions;
     95     }else if(actions){
     96         throw new Error("actions必须是对象")
     97     }
     98 }
     99 //检测是否是一个对象
    100 let isObject=(data)=>{ 
    101     if(Object.prototype.toString.call(data)=="[object Object]"){
    102         return true;
    103     }else{
    104         return false;
    105     }
    106 }
    107 //构建新的组件基类
    108 export default class NewCom extends Component{
    109     shouldComponentUpdate(nextProps){
    110 return event.checkProps(this,nextProps); //检测是否重新渲染该组件 111 } 112 componentWillUnmount(){ 113 event.emptyrProps(); //清空监听列表 114 } 115 }

    使用实例如下:

      

     1 import ReactDom from "react-dom";
     2 import React from "react";
     3 import Component,{connect} from "./react-extend.js";
     4 import * as actions from "./action/test.js";
     5 class Test01 extends Component{
     6     constructor(props){
     7         super(props);
     8         this.props.listenProps(["test01"],this); //监听该组件的动态数据
     9     }
    10     render(){
    11         return <h1>{this.props.test01}</h1>
    12     }
    13 }
    14 class Test02 extends Component{
    15     constructor(props){
    16         super(props);
    17         this.props.listenProps(["test02"],this);  //监听该组件的动态数据
    18     }
    19     clickHandler(){
    20         this.props.actions.changeTest01(789);
    21     }
    22     render(){
    23         return <h1 onClick={this.clickHandler.bind(this)}>{this.props.test02}</h1>
    24     }
    25 }
    26 class Main extends Component{
    27     componentDidMount(){
    28         this.props.actions.init({
    29             test01:123,
    30             test02:456,
    31         })
    32     }
    33     render(){
    34         return <div>
    35             <Test01 {...this.props}/>
    36             <Test02 {...this.props}/>
    37         </div>
    38     }
    39 }
    40 var NewMain=connect(Main,actions);
    41 ReactDom.render(
    42     <NewMain />,
    43     document.getElementById("container")
    44 )

    action:

    1 export function changeTest01(state,value){
    2     return {
    3         test01:value,
    4     }
    5 }
    6 export function init(state,obj){
    7     return obj;
    8 }
  • 相关阅读:
    jmeter之jmx和控件介绍
    Jmeter使用1
    jmeter组件之聚合报告分析
    响应断言
    jmeter组件介绍-线程组、http采样器、结果树
    jmeter目录文件讲解和切换语言
    jmeter 学习 -安装
    关于去除input type='file'改变组件的默认样式换成自己需要的样式的解决方案
    js根据id、value值对checkbox设置选中状态
    javaweb简单的实现文件下载及预览
  • 原文地址:https://www.cnblogs.com/dudeyouth/p/5668706.html
Copyright © 2011-2022 走看看