我正在编写针对 ES5 的 React 拖放教程,但我正在使用 ES6。
这是我的代码:
class Song extends React.Component{
constructor(props){
super(props);
this.state = {isPlaying:false,dragMode:editMode == 1 ? true : false,eligibleToDrag: false};
//this.dragStart = this.dragStart.bind(this);
}
_clickAction(){
if(this.state.dragMode == false){
changeSong(this.props.arrIndex);
playSong();
}
}
dragStart(e){
Array.prototype.forEach.call(document.getElementById('screen2').getElementsByClassName('track'),function(e1){
if(e1.getAttribute('data-songid') == e.currentTarget.getAttribute('data-songid')){
this.setState({eligibleToDrag: false});
console.log('ELIGIBLE?',this.state.eligibleToDrag);
}
else{
this.setState({eligibleToDrag: true});
console.log('ELIGIBLE?',this.state.eligibleToDrag);
}
});
console.log(this.state.eligibleToDrag);
if(e.currentTarget.parentElement.parentElement.id=="screen"){
e.dataTransfer.effectAllowed = 'link';
}
if(e.currentTarget.parentElement.parentElement.id=="screen2"){
e.dataTransfer.effectAllowed = 'move';
}
draggedObject = e.currentTarget;
e.dataTransfer.setData("text/html",e.currentTarget);
}
dragEnd(e){
}
dragOver(e){
e.preventDefault();
var relY = e.clientY - e.target.offsetTop;
var height = e.target.offsetHeight / 2;
if(e.target.parentNode.parentNode.id == 'screen2'){
if(relY > height){
e.target.parentNode.insertBefore(draggedObject,e.target.nextElementSibling);
}
else if(relY < height){
e.target.parentNode.insertBefore(draggedObject,e.target);
}
}
if(e.target.parentNode.parentNode.id == 'screen' && draggedObject.parentNode && draggedObject.parentNode.parentNode.id == 'screen2'){
draggedObject.remove();
//e.stopPropagation();
}
return;
}
render(){
var isDragMode = this.state.dragMode == true;
if(isDragMode){
document.getElementById('screen').classList.add("drag");
document.getElementById('screen2').classList.add("drag");
}
return <div data-songid={this.props.trackInfo.Id} onClick={this._clickAction.bind(this)} className={"track"} draggable={isDragMode ? "true": "false"} onDragEnd={isDragMode ? this.dragEnd.bind(this) : ''} onDragOver={isDragMode ? this.dragOver.bind(this) : ''} onDragStart={isDragMode ? this.dragStart.bind(this) : ''}>
<span draggable={"false"}>{this.props.trackInfo.Title}</span><br draggable={"false"} />
<span draggable={"false"}><i draggable={"false"}>{this.props.trackInfo.Artist}</i></span>
</div>
}
}
在我在dragStart(e)上添加Array.prototype.forEach.call部分之前,该类一直有效。然后它开始在控制台中向我显示“无法读取未定义的属性‘setState’”,指向该部分。我不确定我错过了什么,因为据我所知,我已经在渲染方法中绑定(bind)了所有内容。我的猜测是我还没有绑定(bind)所有内容,但我不确定还能做什么。
最佳答案
原因是在您的 forEach
调用中,变量 this
不再引用您期望的内容。如果您坚持以当前方式执行此操作,则应该在更高的位置声明初始 this
变量并在 forEach
函数中引用它:
...
dragStart(e){
var context = this;
Array.prototype.forEach.call(document.getElementById('screen2').getElementsByClassName('track'),function(e1){
if(e1.getAttribute('data-songid') == e.currentTarget.getAttribute('data-songid')){
context.setState({eligibleToDrag: false}); //change this -> context
console.log('ELIGIBLE?',context.state.eligibleToDrag);
}
else{
context.setState({eligibleToDrag: true});
console.log('ELIGIBLE?',context.state.eligibleToDrag);
}
});
...
但是,由于您使用的是 ES6,您可以使用 Shiny,New,Fat Arrow Function .
...
dragStart(e) {
Array.prototype.forEach.call(document.getElementById('screen2').getElementsByClassName('track'), e1 => {
//use `this` as per usual
}
}
上述情况是可能的,因为 ES6 箭头函数捕获封闭上下文的 this
值
编辑
根据 dandavis 提到的内容,您实际上可以在 forEach
的回调函数中设置 this
的值。它是 forEach 函数的最后一个参数。因此,如果 OP 想要以最快的方式解决这个问题,他只需将 this
附加到他的 forEach
调用的最后一个参数,它就会像魔术一样工作。
Array.prototype.forEach.call(document.getElementById('screen2').getElementsByClassName('track'), function(e1){
//As per usual
},this);
关于javascript - ES6 与 React,无法 setState - 'Cannot read property ' setState' of undefined'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34710927/