2014-09-26 52 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> 
     ); 
    } 
}); 

希望它可以幫助