標籤:
最近一直在思考一個問題,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))); //組合state15 }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} /> //初始化資料放在props46 <App02 content={2} initData={[1,2,3,4,5]}/>47 </div>,48 document.getElementById("container")49 )
最後,希望各位大大能給我指點迷津。剛學不久,可能對react與redux理解還不夠透切,還不清楚這個想法的弊端在哪裡!!!求指教......
react組件渲染的一些想法