我在reactjs-flux上编写了一个简单的应用程序,并且一切正常,只是我收到reactjs的警告,告诉我在未安装的组件上调用setState。
我已经知道这是因为未将挂钩所钩挂的changelistener从商店中删除componentWillUnmount
。我知道这是因为,当我从中打印侦听器列表时,Eventemitter
我看到应该被销毁的侦听器仍然存在,并且当我多次安装/卸载同一组件时,列表会变得更大。
我从BaseStore粘贴代码:
import Constants from '../core/Constants';
import {EventEmitter} from 'events';
class BaseStore extends EventEmitter {
// Allow Controller-View to register itself with store
addChangeListener(callback) {
this.on(Constants.CHANGE_EVENT, callback);
}
removeChangeListener(callback) {
this.removeListener(Constants.CHANGE_EVENT, callback);
}
// triggers change listener above, firing controller-view callback
emitChange() {
this.emit(Constants.CHANGE_EVENT);
}
}
export default BaseStore;
我从遇到此错误的组件中粘贴相关代码(尽管所有组件都会发生此错误):
@AuthenticatedComponent
class ProductsPage extends React.Component {
static propTypes = {
accessToken: PropTypes.string
};
constructor() {
super();
this._productBatch;
this._productBatchesNum;
this._activeProductBatch;
this._productBlacklist;
this._searchById;
this._searchingById;
this.state = this._getStateFromStore();
}
componentDidMount() {
ProductsStore.addChangeListener(this._onChange.bind(this));
}
componentWillUnmount() {
ProductsStore.removeChangeListener(this._onChange.bind(this));
}
_onChange() {
this.setState(this._getStateFromStore());
}
}
在这一点上,这真让我发疯。有任何想法吗?
谢谢!
精简版: expect(f.bind(this)).not.toBe(f.bind(this));
更长的解释:
问题的原因是,EventEmitter.removeListener
要求您传递以前注册的功能EventEmitter.addListener
。如果您传递对任何其他函数的引用,则它是无提示操作。
在您的代码中,您将传递this._onChange.bind(this)
给addListener。bind
返回与此绑定的新函数。然后,您将放弃对该绑定函数的引用。然后,您尝试删除由绑定调用创建的另一个新函数,这是一个空操作,因为从未添加过。
React.createClass自动绑定方法。在ES6中,您需要手动绑定构造函数:
@AuthenticatedComponent
class ProductsPage extends React.Component {
static propTypes = {
accessToken: PropTypes.string
};
constructor() {
super();
this._productBatch;
this._productBatchesNum;
this._activeProductBatch;
this._productBlacklist;
this._searchById;
this._searchingById;
this.state = this._getStateFromStore();
// Bind listeners (you can write an autoBind(this);
this._onChange = this._onChange.bind(this);
}
componentDidMount() {
// listener pre-bound into a fixed function reference. Add it
ProductsStore.addChangeListener(this._onChange);
}
componentWillUnmount() {
// Remove same function reference that was added
ProductsStore.removeChangeListener(this._onChange);
}
_onChange() {
this.setState(this._getStateFromStore());
}
有多种简化绑定的方法-您可以使用ES7@autobind
方法装饰器(例如npm上的autobind-decorator),或编写一个在构造函数中使用调用的autoBind函数autoBind(this);
。
在ES7中,您(希望)能够使用类属性来获得更方便的语法。如果您愿意作为阶段1提案http://babeljs.io/docs/plugins/transform-class-properties/的一部分,可以在Babel中启用它。然后,只需将事件侦听器方法声明为类属性,而不是方法:
_onChange = () => {
this.setState(this._getStateFromStore());
}
由于_onChange的初始值设定项是在构造函数的上下文中调用的,因此arrow函数会自动绑定this
到类实例,因此您可以将其this._onChange
作为事件处理程序传递而无需手动绑定它。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句