繁体   English   中英

从外部访问React状态

[英]Accessing React state from outside

我想使用React.js制作一个应用程序。 我希望它可以轻松地从外部进行自定义(例如,通过编写用户脚本)。 我尝试使用的想法是在根元素状态下创建一些特殊属性(例如sidebarItemsplaylistCreatedHooks ),以便插件开发人员可以在此处添加一些内容。 我的问题是:这是否是一个好方法,是否有Right Way™实现与我的目标相似的目标,最后,插件开发人员将如何使用这些道具?

一种选择是可观察的。 基本上,它是一个对象,您可以听其更改并创建更改。 您还可以在data.playlists上发出其他事件(如“ add”事件)来创建您要提供的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){

});

这是上面使用的Observable的示例(未经测试)实现,带有一个额外的函数,用于生成react组件mixin。

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;
}

这是我的解决方案。 由于有了这个Observable,React组件的状态会自动更新(其结果会像重新渲染组件一样),并且由于.on方法,您甚至可以侦听react之外的更改。

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;
};

示例(使用它在另一个组件上显示警报)://可观察到的init alert_msg = Observable('','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>
        );
    }
});

希望能帮助到你

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM