2014-09-26 53 views
6

我想使用React.js创建应用程序。我希望它可以从外部世界轻松定制(例如通过编写用户脚本)。我试图使用的想法是在根元素状态下创建一些特殊属性(如sidebarItemsplaylistCreatedHooks),所以插件开发人员可以在其中添加某些内容。我的问题是:这是否是一个好方法,是否有正确的方法?实现类似于我的目标的东西,以及最终,插件开发人员如何访问这些道具?从外部访问React状态

回答

8

一个选项是observables。基本上,这是一个可以聆听变化的对象,并在其上创建变更。您也可以发出其他事件,如data.playlists上的“添加”事件来创建您想提供的api。

// data.js 
var data = { 
    sidebarItems: Observable([]), 
    playlists: Observable([]) 
}; 

// app.js 
var App = React.createComponent({ 
    mixins: [data.sidebarItems.mixin("sidebar")], 
    render: function(){ 
    return this.state.sidebar.map(renderSidebarItem); 
    } 
}); 

/// userscript.js 

// causes the view to update 
data.sidebarItems.set(somethingElse); 

// run when someone does data.playlists.set(...) 
data.playlists.on('change', function(playlists){ 

}); 

// an event you could choose to emit with data.playlists.emit('add', newPlaylist) 
data.playlists.on('add', function(newPlaylist){ 

}); 

下面是以上所使用的例子(未测试)实施观察的,与用于产生所述反应成分混入的额外的功能。

var events = require('events'); // or some other way of getting it 
var Observable = function(initialValue){ 
    var self = new events.EventEmitter(); 
    var value = initialValue; 

    self.get = function(){ return value }; 
    self.set = function(updated){ 
    value = updated; 
    self.emit('change', updated); 
    }; 
    self.mixin = function(key){ 
    var cbName = Math.random().toString(); 
    var mixin = { 
     getInitialState: function(){ var o = {}; o[key] = value; return o }, 
     componentDidMount: function(){ 
     self.on('change', this[cbName]); 
     }, 
     componentWillUnmount: function(){ 
     self.removeListener('change', this[cbName]); 
     } 
    } 
    mixin[cbName] = function(){ 
     var o = {}; o[key] = value; this.setState(o); 
    }; 
    return mixin; 
    } 

    return self; 
} 
+0

哇,看起来真棒,谢谢! – Ale 2014-09-26 17:10:09

1

这是我的解决方案。由于这个Observable,React组件的状态会自动更新(其结果如重新渲染组件),您甚至可以通过.on方法来监听反应之外的变化。

var eventEmitter = { 
    _JQInit: function() { 
     this._JQ = jQuery(this); 
    }, 
    emit: function(evt, data) { 
     !this._JQ && this._JQInit(); 
     this._JQ.trigger(evt, data); 
    }, 
    once: function(evt, handler) { 
     !this._JQ && this._JQInit(); 
     this._JQ.one(evt, handler); 
    }, 
    on: function(evt, handler) { 
     !this._JQ && this._JQInit(); 
     this._JQ.bind(evt, handler); 
    }, 
    off: function(evt, handler) { 
     !this._JQ && this._JQInit(); 
     this._JQ.unbind(evt, handler); 
    } 
}; 

var Observable = function(initialValue, name) { 
    var self = eventEmitter; 
    var name = name; 
    var obj = { 
     value: initialValue, 
     ops: self 
    }; 

    self.get = function() { 
     return obj.value 
    }; 

    self.set = function(updated){ 
     if(obj.value == updated) 
      return; 

     obj.value = updated; 
     self.emit('change', updated); 
    }; 

    self.mixin = function() { 
     var mixin = { 
      getInitialState: function() { 
       var obj_ret = {}; 
       obj_ret[name] = obj; 

       return obj_ret; 
      }, 
      componentDidMount : function() { 
       self.on('change', function() { 
        var obj_new = {}; 
        obj_new[name] = obj; 

        this.setState(obj_new); 
       }.bind(this)); 
      } 
     }; 

     return mixin; 
    }; 

    return self; 
}; 

实例(将其用于显示在另一组件的警报): //初始化可观察 alert_msg =可观察( '', 'ALERTMSG');

var ConfirmBtn = React.createClass({ 
    mixins: [alert_msg.mixin()], 
    handleConfirm: function(e) { 
     e.preventDefault(); 

     this.state.alertmsg.ops.set(null); 

     if(! $('#cgv').is(':checked')) { 
      this.state.alertmsg.ops.set('Please accept our terms of conditions'); 
      return; 
     } 
    } 
} 

var AlertPayment = React.createClass({ 
    mixins: [alert_msg.mixin()], 

    render: function() { 
     var style = (this.state.alertmsg === null) ? {display: 'none'} : {display: 'block'}; 

     return (
      <div style={style} className="alertAcceptTerms"> 
       {this.state.alertmsg.value} 
      </div> 
     ); 
    } 
}); 

希望它可以帮助