最近一直在思考一个问题,react的单向数据流面对深层次组件集合(redux connect方法返回的组件,即一项完整的功能)时,数据该如何传递???redux帮助我们解决了什么问题???
我使用了redux+react,发现redux并没有解决react组件之间数据传递问题。只是把数据中心化与避免了父组件取子孙组件的数据时那繁琐的回调,却增加了三个麻烦的东西action、reducer、mapStateProps。复杂的处理流程:action里新增一条数据,reducer就需要增加一个对该数据处理的方法(一般是合并数据,东拼西凑的维护起来略感吃力),再由mapStateProps过滤后传递到组件中。一个很简单的操作用了redux后就会变得很复杂(恶心到爆)!有时候你只想改变组件集合里面一个子组件状态,dispatch后他会把整个组件集合从头到尾渲染一遍(多浪费性能),虽然可以通过componentshouldupdate解决该性能问题,但是觉得好麻烦!不过我们也可以对每个需要独立改变状态的组件都connect一次,这样connect会很频繁,而导致代码沉余,action组织起来也会比较困难。
redux的数据中心化我感觉真的没有必要,因为视图与视图显示的数据本来就需要绑在一起的。redux把数据与视图分离后,阅读起来好吃力:首先要查看组件的事件更新数据的方法--->在action找到更新数据的方法(查看数据源)--->然后再看reducer做了什么处理(好麻烦,难追踪,而且数据中心化后得到的好处我没有发现),我比较喜欢一个事件里有直观的数据操作。所以一直不明白为什么作为前端要把数据集中起来处理?
我想了很久,发现一个组件集合(完整的一项功能)一般情况下只需要把数据初始化一遍。而组件进行的交互一般不会改变组件集合里的所有状态,一个交互只会改变组件集合里一个或者两个的子组件状态。所以我希望当我需要改变一个组件状态时,可以直接改变该组件的状态。这样做组件之间频繁的数据传递就会减少,只有数据初始化的时候才可能需要深层次的数据传递,那怎么做呢???我的思路是把整个页面的所有this.setState()方法收集到一个全局变量下面提供给该页面的所有组件调用,初始化数据由this.props传递!this.props里的所有数据都可以作为组件的初始状态,也可以通过initData该属性设置初始化状态。
//collectSetState.js 1 import{Component} from "react"; 2 //改变react基类,设置默认的constructor 3 export default class newComponent extends Component{ 4 constructor(props){ 5 super(props); 6 getSetState.call(this); 7 } 8 } 9 //收集所以的setState方法 10 export function getSetState(){ 11 this.state=this.props.initData||this.props; //设置该组件的初始化数据 12 window.RX=window.RX?window.RX:{}; let name=this.constructor.name; 13 window.RX[name]=(callback)=>{ //以组件名命名setState方法 window.RX[name].getState=()=>this.state;14 this.setState(Object.assign({},this.state,callback.call(this))); //组合state 15 } 16 }
例子:
1 import ReactDOM from "react-dom"; 2 import React from "react"; 3 import Component,{getSetState} from "./collectSetState.js"; //改造后的基类组件(构造方法会默认的收集该组件的setState方法) 4 class App01 extends Component{ 5 constructor(props){ 6 super(props); 7 getSetState.call(this) //自定义构造时可用通过getSetState收集setState方法 8 } 9 render(){ 10 return <h1>{this.state.content}</h1>; 11 } 12 } 13 class App02 extends Component{ 14 mapChild(){ 15 return this.state.data.map((item)=>{ 16 return <p>{item+this.state.content}</p>; 17 }) 18 } 19 render(){ 20 return <div> 21 <h1 >{this.state.content}</h1> 22 {this.mapChild()} 23 </div> 24 ; 25 } 26 } 27 class Controller extends Component{ 28 clickHandler(e){ 29 RX[e.target.value](function(){ //根据组件名来使用收集的setState方法 30 return { 31 content:(this.state.content+1)||0, //返回修改的状态 32 } 33 }) 34 } 35 render(){ 36 return <div> 37 <input type="button" value="App01" onClick={this.clickHandler.bind(this)}/> 38 <input type="button" value="App02" onClick={this.clickHandler.bind(this)}/> 39 </div>; 40 } 41 } 42 ReactDOM.render( 43 <div> 44 <Controller /> 45 <App01 content={1} /> //初始化数据放在props 46 <App02 content={2} initData={[1,2,3,4,5]}/> 47 </div>, 48 document.getElementById("container") 49 )
最后,希望各位大大能给我指点迷津。刚学不久,可能对react与redux理解还不够透切,还不清楚这个想法的弊端在哪里!!!求指教......