你的位置:首页 > Java教程

[Java教程]react组件数据通信



  今天看到一篇文章说react已经成熟了(可能说的是react的社区已经成熟了),react这个框架我觉得还没有完美。因为让人头疼的深层次组件通信还没有很好的解决方案,这个问题没有解决react的开发效率根本提不上去。

  前段时间我在研究react+redux,发现redux并没有完美的解决react的通信问题。只是把数据中心化管理与完善了react大单向数据流(避免回调取值),redux增加三个经常需要维护的东西:action,reducer,mapStateToProps。在普通项目上这样频繁的操作真的很烦人(恶心)......。对于redux的数据中心化管理(action)我还是挺喜欢的,而reducer与mapStateToProps就觉得没必要了!

  redux并不是我想要的解决方法,所以我寻求了自己的解决方法,我对react的Component的基类进行了扩展,给每个组件都添加了Component.setState,Component.getState,Component.getProps方法提供给页面的其他组件使用包括自己,当然也可以使用原生的this.setState方法类更新状态。同时我给Component.setState扩展方法提供与redux的一样的数据中心化机制(redux的action)具体实现如下:

 // reactExtend.js
1 import{Component} from "react"; 2 //扩展基类,使继承该基类的子类自动收集getState与setState方法 3 export default class newComponent extends Component{ 4 constructor(props){ 5 super(props); 6 createStateTool.call(this); 7 } 8 } 9 //收集getState与setState方法10 export function createStateTool(){11 const isObject=verifyObject(this.props.defaultState);12 if(typeof this.props.defaultState!="undefined"&&!isObject){13 throw new Error("组件的默认状态必须是一个对象!");14 }15 this.state=isObject?this.props.defaultState:this.props;16 //设置状态17 this.constructor.setState=(data,res,callback)=>{18 var merge={}; //合并的数据19 callback=typeof callback=="function"?callback:function(){};20 if(typeof res!=="undefined"&&typeof res!=="function"&&!verifyObject(res)){21 throw new Error("参数2:值只能是方法或对象");22 }23 //原生setState的回调方法24 if(typeof res=="function"){25 callback=res;26 }27 if(verifyObject(res)){28 merge=res;29 }30 if(typeof data==="function"){31 return (...param)=>{32 var newState=data.call(this,...param);33 //action返回的是方法的时候给它传入this.constructor.setState方法34 if(typeof newState==="function"){35 //异步操作处理与redux-thunk实现方式一样36 newState(this.constructor);37 return false;38 }39 if(!verifyObject(newState)){40 throw new Error("action返回的必须是对象!");41 }42 this.setState(Object.assign({},this.state,merge,newState),callback);43 }44 }else if(verifyObject(data)){45 this.setState(Object.assign({},this.state,merge,data),callback);46 }47 }48 //获取状态49 this.constructor.getState=()=>{50 return Object.assign({},this.state);51 }52 //获取属性53 this.constructor.getProps=()=>{54 return Object.assign({},this.props);55 }56 }57 //检测是否是一个对象58 function verifyObject(data){59 if(Object.prototype.toString.call(data)=="[object Object]"){60 return true;61 }else{62 return false;63 }64 }

 


   既然提供了action,当然也要实现与redux一样的包装方法啦。所以提供了bindAction方法对action的所有方法进行包装,实现调用action方法就会自动调用Component.setState方法。代码如下:

 1 //包装actions 2 var bindActionCreators=(action)=>(...data)=>(component,...param)=>{ 3   component.setState(action,...param)(...data); 4 } 5 //检测是否是一个对象 6 var verifyObject=(data)=>{ 7   if(Object.prototype.toString.call(data)=="[object Object]"){ 8     return true; 9   }else{10     return false;11   }12 }13 var bindAction;14 export default bindAction=(action)=>{15   if(typeof action=="function"){16     return bindActionCreators(action);17   }18   if(verifyObject(action)){19     var newAction={};20     var keys=Object.keys(action);21     for(var i=0;i<keys.length;i++){22       newAction[keys[i]]=bindActionCreators(action[keys[i]]);23     }24   }25   return newAction; 26 }

 

实例如下:


  action代码块:用过redux的朋友都知道action就是为了把数据集中化管理,动态数据都会存放在这里。作为Component.setState参数的action方法可以通过this.state获取该组件的状态。

 

 // actions.js
1 export function add(data){
    //支持异步 2 return (component)=>{ 3 component.setState(function(){ 4 return { 5 content:(this.state.content+1+data)||0, 6 } 7 })(); 8 } 9 }10 export function cut(data){11 return {12 content:(this.state.content-1-data)||0,13 }14 }

 

 

 

 

  只要组件继承于扩展基类并且存在于该模块,在该模块里面可以任意改变该组件的状态与获取该组件的状态及属性。下面是一个简单的例子:

 // demo.js
1 import ReactDOM from "react-dom"; 2 import React from "react"; 3 import * as actions from "./actions.js"; 4 import bindAction from "./bindStateToAction.js"; 5 import Component,{createStateTool} from "./reactExtend.js"; //改造后的父类组件(构造方法会默认的收集该组件的setState方法) 6 var newactions=bindAction(actions); //包装actions 7 class App01 extends Component{ 8 constructor(props){ 9 super(props);10 createStateTool.call(this) //自定义构造是收集getState与setState方法11 }12 render(){13 return <h1>{this.state.content}</h1>;14 }15 }16 class App02 extends Component{17 mapChild(){18 return this.props.data.map((item)=>{19 return <p key={item}>{item+this.state.content}</p>;20 })21 }22 render(){23 return <div>24 <h1 >{this.state.content}</h1>25 {this.mapChild()}26 </div>27 ;28 }29 }30 class Controller extends Component{31 app02ClickHandler(e){32 //设置App02组件的状态33 App02.setState(actions.add)(5) //没有包装action的写法 App02.setState(actions.add)(5) App02--->需要设置状态的组件 actions.add--->action方法 5--->action方法的参数34   //App02.setState(actions.add(5))也支持这种写法,但是这种写法的actions方法是不支持通过this获取组件的状态及属性
      //App02.setState({content:1}) 也可以直接传入数据
      //App02.setState({content:1},App01.getState()) 合并App01的状态
    }35 app01ClickHandler(e){36 //设置App01组件的状态37 newactions.cut(5)(App01) ////包装的action的写法 action.cut(5)(App01) 5--->action.cut参数 App01--->需要设置状态的组件
       //newactions.cut(5)(App01,App02.getState()) 合并App02的状态
      /newactions.cut(5)(App01,function(){}) this.setState设置完毕后回调
38 }39 render(){40 return <div>41 <input type="button" value="App02" onClick={this.app02ClickHandler.bind(this)}/>42 <input type="button" value="App01" onClick={this.app01ClickHandler.bind(this)}/>43 </div>;44 }45 }46 ReactDOM.render(47 <div>48 <Controller />49 <App01 content={100} test={123456}/> 50 <App02 defaultState={{content:2}} data={[1,2,3,4,5]}/>51 </div>,52 document.getElementById("container")53 )

 


   这样的做法是不是很方便很灵活?我准备把这个扩展用到项目上,但是有点担心出什么幺蛾子。毕竟刚接触react不久,还没有完全掌握,请各位大大指出做法的弊端在哪里???