我正在学习React,尝试使用浏览器HTML5文件API创建一个简单的Tweetbox“上传”多个图像。
见下面的截图:
正如官方文档中所建议的那样,我使用内置的map函数来遍历数组中上传的图片网址。
我将它包含在一个变量中,以便它可以在包装器div中的下面的JSX中重用,我只想在上传图像时显示它。
问题在于,由于某种范围问题,它无法“看到”或“访问”我的_removePhoto函数并点击此代码段中的处理程序:
_removePhoto(event) {
let array = this.state.imagePreviewUrls;
let index = array.indexOf(event.target.result)
array.splice(index, 1);
this.setState({imagePreviewUrls: array });
// this.setState( {imagePreviewUrls: false} );
}
render() {
let {imagePreviewUrls} = this.state;
let {thereIsImage} = this.state;
// var {thereIsImage} = this.state;
// onClick={this._removePhoto}
var imageList = imagePreviewUrls.map(function(value, index) {
return (
<figure className="ma0 relative flex items-center justify-center">
<button onClick={this._removePhoto} className="button-reset pointer dim bn bg-black h2 w2 br-100 white flex items-center justify-center absolute absolute--fill-l center"><i className="material-icons f5">close</i>
</button>
<img key={index} src={value} className="h3 w3" />
</figure>
)
})
这给出了错误:
Uncaught TypeError: Cannot read property '_removePhoto' of undefined
at bundle.js:19085
at Array.map (<anonymous>)
(如果我没有以这种方式将map函数括在imageList变量中,则_removePhoto逻辑有效。)
此外,如果我删除onClick事件处理程序,它会显示图像预览,但控制台中还有另一个错误,说我需要包含“index”。但是,我已根据文档的说明将其包括在内。
以下是我的完整代码:
import React from 'react'
import ReactDOM from 'react-dom'
// This library didn't help me solve the problem
// const classNames = require('classnames');
class TweetBox extends React.Component {
constructor(props) {
super(props);
this.state = {
text: "",
files: [],
imagePreviewUrls: [],
thereIsImage: false
};
this._handleTextChange = this._handleTextChange.bind(this);
this._triggerFileDialogue = this._triggerFileDialogue.bind(this);
this._handlePhotoUpload = this._handlePhotoUpload.bind(this);
this._removePhoto = this._removePhoto.bind(this);
}
_removePhoto(event) {
let array = this.state.imagePreviewUrls;
let index = array.indexOf(event.target.result)
array.splice(index, 1);
this.setState({imagePreviewUrls: array });
// this.setState( {imagePreviewUrls: false} );
}
render() {
let {imagePreviewUrls} = this.state;
let {thereIsImage} = this.state;
// var {thereIsImage} = this.state;
// onClick={this._removePhoto}
var imageList = imagePreviewUrls.map(function(value, index) {
return (
<figure className="ma0 relative flex items-center justify-center">
<button onClick={this._removePhoto} className="button-reset pointer dim bn bg-black h2 w2 br-100 white flex items-center justify-center absolute absolute--fill-l center"><i className="material-icons f5">close</i>
</button>
<img key={index} src={value} className="h3 w3" />
</figure>
)
})
return (
<div>
{/* TITLE SECTION */}
<div className="pv2 tc bb b--black-10">
<h1 className="ma0 f5 normal">Create New Report</h1>
</div>
<div className="bg-near-white pa3">
<textarea onChange={this._handleTextChange} placeholder="Write your report here" name="tweet" rows="4" className="w-100 br2 ba b--black-10 pa2"></textarea>
{ imagePreviewUrls.length > 0 &&
<div className="bg-black-10 pa2 flex">
{imageList}
</div>
}
<input className="hide" ref={ (input) => { this.fileInput = input; } } onChange={ this._handlePhotoUpload } type="file"></input>
<div className="mt3 flex justify-between">
<button onClick={ this._triggerFileDialogue } className="button-reset flex items-center br2 bn bg-transparent blue hover-bg-black-10 pointer">
<i className="material-icons f3">photo_camera</i>
</button>
<div className="flex items-center">
<button disabled={ this.state.text.length === 0 } className="button-reset bg-blue bn white f6 fw5 pv2 ph3 br2 dim">Message</button>
</div>
</div>
{/* End "near-white" subcontainer */}
</div>
{/* End "b--black-10" parent container */}
</div>
);
} // End Render
_handleTextChange(event) {
this.setState( { text: event.target.value } );
// For debugging:
// console.log( { text: event.target.value })
}
_triggerFileDialogue(event) {
this.fileInput.click();
}
_handlePhotoUpload(event) {
// var self = this;
event.preventDefault();
let files = event.target.files;
for (let i = 0; i < files.length; i++) {
let reader = new FileReader();
reader.onloadend = (evt) => {
var imageString = evt.target.result;
let updatedImages = this.state.imagePreviewUrls.concat(imageString);
this.setState({
imagePreviewUrls: updatedImages,
files: files[i],
thereIsImage: true
});
}
reader.readAsDataURL(files[i]);
console.log(files[i]);
}
}
} // End Master React Class
ReactDOM.render( <TweetBox />, document.getElementById("app") );
非常感谢,我已经在Stack Overflow上搜索了很多东西,但找不到解决方案!上面的代码应该是可重现的。
答案 0 :(得分:3)
而不是在map
上使用匿名函数,你应该使用箭头函数(它们自动绑定到当前上下文):
var imageList = imagePreviewUrls.map((value, index) => {
return (
<figure className="ma0 relative flex items-center justify-center">
<button onClick={this._removePhoto} className="button-reset pointer dim bn bg-black h2 w2 br-100 white flex items-center justify-center absolute absolute--fill-l center"><i className="material-icons f5">close</i>
</button>
<img key={index} src={value} className="h3 w3" />
</figure>
)
})
使用箭头功能时,
this
会自动引用您在相关环境中的当前this
。