我正在研究为ES5做的反应拖放教程,但我正在使用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',指向该部分。我不知道我错过了什么,因为据我所知,我已经在渲染方法中绑定了所有内容。我的猜测是我没有绑定所有内容,但我不确定还能做什么。
答案 0 :(得分:2)
原因是在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 Arrow函数捕获封闭上下文的this
值
修改
从dandavis提到的内容中添加,您实际上可以在this
的回调函数中设置forEach
的值。它是forEach函数的最后一个参数。因此,如果OP希望以最快的方式解决这个问题,他可以将this
附加到forEach
来电的最后一个参数中,它就像魔法一样。
Array.prototype.forEach.call(document.getElementById('screen2').getElementsByClassName('track'), function(e1){
//As per usual
},this);