[英]Accessing React state from outside
I want to make an app using React.js. 我想使用React.js制作一个应用程序。 I want it to be easily customizable from the outside world (eg by writing userscripts). 我希望它可以轻松地从外部进行自定义(例如,通过编写用户脚本)。 The idea I attempted to use is to make some special properties in the root element state (like sidebarItems
or playlistCreatedHooks
) so addon developers could add something there. 我尝试使用的想法是在根元素状态下创建一些特殊属性(例如sidebarItems
或playlistCreatedHooks
),以便插件开发人员可以在此处添加一些内容。 My questions are: is this a good way to do so, is there the Right Way™ to achieve something similar to my goal and, finally, how will addon developers access these props? 我的问题是:这是否是一个好方法,是否有Right Way™实现与我的目标相似的目标,最后,插件开发人员将如何使用这些道具?
One option is observables. 一种选择是可观察的。 Basically it's an object you can listen to changes on, and create a change on. 基本上,它是一个对象,您可以听其更改并创建更改。 You could also emit other events like an 'add' event on data.playlists to create the api you want to provide. 您还可以在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){
});
Here's an example (untested) implementation of Observable used above, with an extra function for generating the react component mixin. 这是上面使用的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;
}
Here is my solution. 这是我的解决方案。 Thanks to this Observable the React components' state are automatically updated (with its consequences, like re-render the component) and you can even listen for changes outside react thanks to the .on
method. 由于有了这个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;
};
example (using it for showing an alert on another component): //Observable init alert_msg = Observable('', 'alertmsg'); 示例(使用它在另一个组件上显示警报)://可观察到的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>
);
}
});
Hope it helps 希望能帮助到你
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.