上载图片时setState异步

时间:2018-08-06 05:31:49

标签: reactjs

我需要将文件上传到服务器,因为我已经为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显示为空时没有得到数据。

预先感谢

2 个答案:

答案 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>
    );
}