我需要将文件上传到服务器,因为我已经为onClick事件提供了fileChangedHandler函数。但是在该函数中,setState由于异步操作而被跳过。 我在下面提供我的代码。
class MultiSelectField extends React.Component {
constructor(props) {
super(props);
this.state = { //image: '',
selectedFile: null};
this.fileChangedHandler = this.fileChangedHandler.bind(this);
this.fileUploadHandler = this.fileUploadHandler.bind(this)
}
fileChangedHandler = (event) => {
this.setState({selectedFile:event.target.files[0]}) // asynch and skipping
console.log(this.state.selectedFile)
this.forceUpdate()
}
fileUploadHandler = () => {
const fd = new FormData()
fd.append('myFile', this.state.selectedFile, this.state.selectedFile.name)
axios.post('my-domain.com/file-upload', formData)
console.log("selected"+JSON.stringify(this.state.selectedFile))
console.log("form data : "+fd)
}
render() {
return (
<div>
<input type="file" onChange={this.fileChangedHandler} ref="file" />
<button onClick={this.fileUploadHandler}>Upload!</button>
</div>
);
}
}
我安慰this.state.selectedFile
显示为空时没有得到数据。
预先感谢
答案 0 :(得分:1)
您可以最初隐藏Upload
按钮,并在将选定文件设置为回调状态后显示它。
fileChangedHandler = (event) => {
this.setState({selectedFile:event.target.files[0], showUploadButton:true}, () =>{
// file has been selected
console.log(this.state.selectedFile) <-- console.log in callback
}) // asynch and skipping
this.forceUpdate()
}
渲染
{this.state.showUploadButton && <button onClick={this.fileUploadHandler}>Upload!</button>}
将文件设置为状态后,现在将显示“上传”按钮,然后您将得到它。
但是您的问题依赖于此-
在如上所述设置状态后,此行应位于回调函数内部。
console.log(this.state.selectedFile)
回调setState
方法可确保已设置状态。
更新
fileChangedHandler = (event) => {
this.setState({selectedFile:event.target.files[0], showUploadButton:true}, () => {
console.log(this.state.selectedFile)
this.forceUpdate()
})
}
那为什么行得通?
反应setState
方法是asynchronous
,这就是在组件中设置状态时通过callback
接收确认的原因。
您可能会想到另一个问题,即为什么它是异步的,而不调用任何外部资源来设置状态(API或服务器调用)。
简单的答案是-
由于React组件中的每个状态更改,它都会重新呈现render()
方法或虚拟DOM。现在,假设您一次单击即可在一个组件中设置100个状态,那么这应该呈现100次的虚拟DOM。哪个反应实际上不起作用。
它创建一批状态。将100s状态分为2-3批。现在,从UI角度来看,它可以一次接受多个状态,但是可以通过将状态分组为几个批次来成批设置它们,以使UI保持自由且处于非阻塞状态。
这就是为什么术语asynchronous
被用来setState
的原因。
答案 1 :(得分:0)
使用setState回调调用forceUpdate是不必要的-设置状态将强制更新(新渲染);)
在更改完成后将状态设置为触发时,可以使用回调-在这种情况下,将手动触发以下操作。吻&可读;)
fileChangedHandler = (event) => {
this.setState({selectedFile:event.target.files[0]})
}
您可以在简单情况下禁用上传按钮
render() {
return (
<div>
<input type="file" onChange={this.fileChangedHandler} ref="file" />
<button onClick={this.fileUploadHandler} disabled={!this.state.selectedFile}>Upload!</button>
</div>
);
}
或隐藏它
render() {
return (
<div>
<input type="file" onChange={this.fileChangedHandler} ref="file" />
{!this.state.selectedFile &&
<button onClick={this.fileUploadHandler}>Upload!</button>
}
</div>
);
}