码迷,mamicode.com
首页 > 其他好文 > 详细

react组件数据通信---扩展(2)

时间:2016-05-13 08:56:20      阅读:329      评论:0      收藏:0      [点我收藏+]

标签:

  对于react来说使用redux来管理状态是个不错的方案,redux是个很好的数据管理框架。但是redux并不是专门给react定制的数据管理框架,所以用它来管理react的数据也只能是凑合着用。redux麻烦的数据操作让我很反感,所以我想弄出一套适合自己的数据管理方式。

  思路如下:扩展react的基类Component,扩展的基类构造里监听组件里的数据。监听的列表其实就是一个完整的状态树,组件名与组件的状态数据 一 一对应关系(组件与数据之间清晰的关系),整个页面的操作我只需要维护这个状态树。对于共享数据(状态)的问题,我收集了一份数据与组件依赖关系列表(数据:[组件、组件]),更新数据时通过数据来查找需要更新的组件集合逐一setState。

具体实现如下:

    

  1 import React,{Component} from "react";
  2 var setStateList={};
  3 export default class newComponent extends Component{
  4     constructor(props){
  5         super(props);
  6         this.props.listener&&event.listener(this.constructor.name,this.props.listener);
  7         setStateList[this.constructor.name]=setState.bind(this);   //收集每个组件的setState方法
  8         this.constructor.listener=event.listener;   //提供监听接口,可以监听额外数据
  9         this.constructor.dispatch=event.dispatch;  //发布接口
 10         this.constructor.getData=event.getData;
 11         this.init&&this.init();  //组件初始化提供接口
 12         setData.call(this); //更新属性
 13     }
 14     shouldComponentUpdate(nextProps, nextState){
 15         setData.call(this,nextProps,nextState);
 16         return this.ComponentUpdate?this.ComponentUpdate(nextProps, nextState):true;
 17     }
 18 }
 19 function setData(props=this.props,state=this.state){
 20     if(props.listener){
 21         //
 22         var data=Object.assign(props.listener,(this.data||{}),state);
 23         delete data.listener;
 24     }
 25     //提供给组件使用的数据,因为react的this.props很难维护,所以添加了新的属性this.toProp来代替this.props
 26     this.data=data?data:Object.assign({},state);
 27 }
 28 function setState(data){
 29     var component=this.constructor.name,
 30         props=event.getData(component);
 31         if(isObject(data)){
 32             //更新状态
 33             this.setState(props?Object.assign(props,data):data);
 34         }
 35 }
 36 var event=(()=>{
 37     var listenerData={},  //组件数据列表
 38         updateComponents={};  //依赖列表,以数据决定依赖
 39     function listener(type,data){   //监听数据
 40         if(typeof type!=="string"&&isObject(type)){
 41             data=type;
 42             type=this.name;
 43         }
 44         if(isObject(data)){
 45             listenerData[type]=data;
 46             updateComponents[data]?updateComponents[data].push(type):updateComponents[data]=[type];
 47         }
 48     }
 49     function getData(type,status){
 50         type=type||this.name;
 51         if(status){
 52             return Object.assign({},listenerData[type]);  //获取的组件数据
 53         }else{
 54             return listenerData[type];
 55         }
 56     }
 57     function dispatch(data,status){   //更新状态并处理依赖,param监听一个方方法的参数,status=true开启更新依赖模式
 58         var type=this.name;  //组件名
 59         var components=updateComponents[listenerData[type]];   //获取使用该数据该的组件
 60             if(!isObject(data)&&data!=="function"){
 61                 throw new Error("dispatch参数错误!");
 62             }
 63             if(typeof data==="function"){
 64                 data(this);
 65                 return false;
 66             }
 67             if(!components){
 68                 listener(type,data);
 69                 components=[type];
 70             }
 71         if(!status){
 72             setStateList[type](data);
 73             return false;
 74         }
 75         //更新所有使用了该数据的组件
 76         components.forEach((item)=>{
 77             setStateList[item](data);
 78         })
 79     }
 80     return {
 81         listener:listener,
 82         getData:getData,
 83         dispatch:dispatch,
 84     }
 85 })();
 86 var isObject=(data)=>{
 87     return (Object.prototype.toString.call(data).indexOf("object")!=-1);
 88 }
 89 //包装actions
 90 let bindActionCreators=(action)=>(...param)=>(component)=>{
 91     component.dispatch(action(event.getData(component.name),...param));
 92 }
 93 export let bindAction=(action)=>{
 94     if(typeof action=="function"){
 95         return bindActionCreators(action);
 96     }
 97     if(isObject(action)){
 98         var newAction={};
 99         var keys=Object.keys(action);
100         for(var i=0;i<keys.length;i++){
101             newAction[keys[i]]=bindActionCreators(action[keys[i]]);
102         }
103     }
104     return newAction; 
105 }

 

例子:

action

 1 export function cut(state,data){
 2     return {
 3         type:"CUT",
 4         content:(state.content-1)||0,
 5     }
 6 }
 7 export function addNav(state){
 8     state.nav.push({
 9         name:"微坛02",
10         id:15,
11         children:[
12             {
13                 name:"管理",
14                 id:16,
15                 children:[
16                     {
17                         name:"邦德",
18                         id:17,
19                     }
20                 ]
21             },
22             {
23                 name:"管理",
24                 id:18,
25                 children:[
26                     {
27                         name:"邦德",
28                         id:19,
29                     },
30                     {
31                         name:"火种",
32                         id:20,
33                     }
34                 ]
35             }
36         ]
37     })
38     return state;
39 }
40 export function createNav(){
41     return (component)=>{
42         setTimeout((res)=>{
43             component.dispatch({
44                 nav:[{
45                         name:"药联",
46                         id:1,
47                         children:[
48                             {
49                                 name:"海景",
50                                 id:2,
51                                 children:[
52                                     {
53                                         name:"邦德",
54                                         id:3,
55                                     }
56                                 ]
57                             }
58                         ]
59                     },
60                     {
61                         name:"微坛",
62                         id:4,
63                         children:[
64                             {
65                                 name:"管理",
66                                 id:5,
67                                 children:[
68                                     {
69                                         name:"邦德",
70                                         id:6,
71                                     }
72                                 ]
73                             },
74                             {
75                                 name:"管理",
76                                 id:7,
77                                 children:[
78                                     {
79                                         name:"邦德",
80                                         id:8,
81                                     },
82                                     {
83                                         name:"火种",
84                                         id:9,
85                                     }
86                                 ]
87                             }
88                         ]
89                     }]
90                 })
91         },1000)
92     }
93 }

 

 

 1 import ReactDOM from "react-dom";
 2 import React from "react";
 3 import {Col,Button,Row,Menu, Icon }from "antd";
 4 import * as actions from "../actions/actions.js";
 5 import Component,{bindAction} from "../react-extend.js"; //改造后的父类组件(构造方法会默认的收集该组件的setState方法)
 6 var newactions=bindAction(actions);
 7 const SubMenu = Menu.SubMenu;
 8 const MenuItemGroup = Menu.ItemGroup;
 9 class Nav extends Component{
10     init(){
11         newactions.createNav()(Nav);
12     }
13     mapItem(){
14         var keys=Math.random()*15+1;
15         var loop=(data,Node,key="")=>{
16             return data&&data.map((item,index)=>{
17                 keys++;
18                 if(Node&&item.children){
19                     return <Node key={keys} title="分组1">{loop(item.children,null,"setting:")}</Node>
20                 }
21                 else if(item.children){
22                     return <SubMenu key={"SubMenu"+keys} title={<span><Icon type="setting" />{item.name}</span>}>
23                         {loop(item.children,MenuItemGroup)}
24                     </SubMenu>
25                 }else{
26                     return <Menu.Item key={key+keys}>
27                         <Icon type="mail" />{item.name}
28                     </Menu.Item>
29                 }
30             })
31         }
32         return loop(this.data.nav||[])
33     }
34     render(){
35         this.data.nav&&Other.dispatch(this.data.nav[0])
36         return <div>
37             <Menu mode="horizontal">
38                 {this.mapItem()}
39              </Menu>
40              <Test listener={this.data} test="添加菜单"/>
41          </div>
42     }
43 }
44 class Test extends Component{
45     init(){
46 
47     }
48     clickHanlder(){
49         newactions.addNav()(Nav)
50     }
51     restHanlder(){
52         newactions.createNav()(Nav);
53     }
54     render(){
55         return <div>
56                     <h1 onClick={this.clickHanlder.bind(this)}>{this.props.test}</h1>
57                     <p onClick={this.restHanlder.bind(this)}>重置</p>
58                </div>;
59     }
60 }
61 class Other extends Component{
62     render(){
63         return <p>{this.data.name}</p>
64     }
65 }
66 ReactDOM.render(
67     <div>
68         <Nav />
69         <Other />
70     </div>,
71     document.getElementById("container")
72 )

 

槽点:改变了react的constructor与shouldComponentUpdate的使用方式:constructor=>init、shouldComponentUpdate=>ComponentUpdate、V层使用this.data输出动态数据。由于使用比较灵活,没有限制,没有好的使用规范可能会导致组件之间交叉数据过于复杂,难以维护!

react组件数据通信---扩展(2)

标签:

原文地址:http://www.cnblogs.com/dudeyouth/p/5483365.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!