Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upload file.status is always being uploading #2423

Closed
imxiongying opened this issue Jul 18, 2016 · 105 comments
Closed

Upload file.status is always being uploading #2423

imxiongying opened this issue Jul 18, 2016 · 105 comments

Comments

@imxiongying
Copy link

@imxiongying imxiongying commented Jul 18, 2016

本地环境

  • antd 版本:1.6.5
  • 操作系统及其版本:mac 10.11.5
  • 浏览器及其版本:50.0.2661.102

你做了什么?

1.6.5版本 Upload控件onChange方法只会执行一次,且info.file.status一直为uploading,http请求正常,返回200。
降级为1.6.4之后正常使用,uploading之后info.file.status为done

你期待的结果是:

实际上的结果:

可重现的在线演示

@afc163
Copy link
Member

@afc163 afc163 commented Jul 19, 2016

我实测是没有问题的,方便给出有问题的完整代码以方便重现么?

@imxiongying
Copy link
Author

@imxiongying imxiongying commented Jul 19, 2016

@afc163
Copy link
Member

@afc163 afc163 commented Jul 19, 2016

对于受控模式,你应该在 onChange 中始终 setState fileList,保证所有状态同步到 Upload 内。类似这里的写法:http://ant.design/components/upload/#components-upload-demo-fileList

// good

onFileChange(fileList) {
  if ( ... ) {
    ...
  } else {
    ...
  }
  // always setState
  this.setState({ fileList: [...fileList] });
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />
// bad

onFileChange(fileList) {
  if ( ... ) {
    this.setState({ fileList: [...fileList] });
  } else {
    ...
  }
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />

建议研习受控组件概念:https://facebook.github.io/react/docs/forms.html#controlled-components


注意需要克隆 fileList 以保障 Upload 能感知数组变化。

- this.setState({ fileList });
+ this.setState({ fileList: [...fileList] });

@afc163
Copy link
Member

@afc163 afc163 commented Oct 11, 2016

@hull123
Copy link

@hull123 hull123 commented Mar 2, 2017

我使用Upload控件为什么总是上传失败,总是报错:POST http://localhost:8081/api/nes/2/uploadMusic/r_ty 404 (Not Found)

@Adam-Ggogoing
Copy link

@Adam-Ggogoing Adam-Ggogoing commented Apr 28, 2017

对于有限制的url怎么去增加身份标识字段和token之类的用action怎么去传?action只给地址,不能加上data么?

@yongningfu
Copy link

@yongningfu yongningfu commented Jun 8, 2017

在 React.PureComponent 里面还是有问题的 因为React.PureComponent里面做了一层优化判断,filelist有缓存引用, 认为是同一个对象就不会更新, 在React.PureComponent立马 应该生成一个新的对象
handleChange = ({ fileList }) => {
// fixed bug
this.setState({ fileList: fileList.slice() });
}

@afc163

@afc163
Copy link
Member

@afc163 afc163 commented Jun 8, 2017

@yongningfu 感谢提示,已更新。

@TongDaDa
Copy link

@TongDaDa TongDaDa commented Sep 20, 2017

特别提醒一下 : 在使用React shouldComponentUpdate 进行浅比较时,在受控模式当中,即使状态同步到 Upload 内,也不会更新的哦。原因是引用全等===,导致阻止render

@bang0929
Copy link

@bang0929 bang0929 commented Dec 21, 2017

上传多张图片,beforeUpload设置上传图片参数限制,onChange获取上传成功的图片列表,上传成功几张图片后,上传一张错误的图片,会将前面上传成功的图片全部清除,请问有什么解决办法吗?

@SummerSMJ
Copy link

@SummerSMJ SummerSMJ commented Jan 25, 2018

当你回调的时候应该重新设置一下status 比如这样 this.setState( {fileList});

handleChange = (info) => {
console.log(info);

    //把fileList拿出来
    let {fileList} = info;

    const status = info.file.status;
    if (status !== 'uploading') {
        console.log(info.file, info.fileList);
    }
    if (status === 'done') {
        message.success(`${info.file.name} file uploaded successfully.`);
    } else if (status === 'error') {
        message.error(`${info.file.name} file upload failed.`);
    }

    //重新设置state
    this.setState( {fileList});
}

@hoozi
Copy link

@hoozi hoozi commented Mar 28, 2018

这么说onChange只要是状态有变化,Upload内部就一直在调用,是这样吗

@wv1124
Copy link

@wv1124 wv1124 commented Apr 28, 2018

这个问题坑了半天,原来要setState一下。组件不应该设计成这样的,为什么依懒外部状态?

@fengyansuowang
Copy link

@fengyansuowang fengyansuowang commented May 9, 2018

我只想要那个base64码,不跟后台交互,怎么样解决自动向后台发请求的问题哦?

@tauil
Copy link

@tauil tauil commented Jun 27, 2019

It fixed to me when I started using React.Component instead of React.PureComponent.

@jesome
Copy link

@jesome jesome commented Jul 12, 2019

When I use modal.info and control filelist, onChange is only called once. But when I remove Modal, it works

@fireairforce
Copy link
Member

@fireairforce fireairforce commented Sep 8, 2019

可以

@zhuxx2021
Copy link

@zhuxx2021 zhuxx2021 commented Oct 23, 2019

1: 使用React.Component
2: 注意检查getDerivedStateFromProps里面是否设置了fileList,是否设置正确。
3: fileList: this.state.fileList
4: onChange: ({file, fileList}) => {
this.setState({fileList});
}

@lh1991
Copy link

@lh1991 lh1991 commented Mar 26, 2020

3.19.7还有这个问题

@whg517
Copy link

@whg517 whg517 commented Mar 31, 2020

I post a successful case for your reference. I've had this problem before, though. Also calculate here make a note, in order to facilitate oneself forgot convenient search later

env:

  • antd: 4.0.0-rc.1
  • pro-layout: 5.0.0
  • react: 16.9.17
import React, { useState } from 'react';
import { Modal, Upload, Button, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons/lib';
import { UploadProps } from 'antd/lib/upload';
import { deleteArtifact } from '@/services/artifact';

interface UploadModalType {
  visible: boolean
  onCancel: () => void
  projectId: number
}

const UploadModal: React.FC<UploadModalType> = props => {
  const { visible, onCancel, projectId } = props;
  const [fileList, setFileList] = useState();

  const uploadProps: UploadProps = {
    name: 'file',
    fileList,
    listType: 'text',
    action: 'http://localhost:8080/v1/artifacts',
    data: { project_id: projectId, type: 'application/json' },
    onChange(info) {

      setFileList(info.fileList.slice()); // Note: A new object must be used here!!!

      if (info.file.status === 'done') {
        message.success(`${info.file.name} file uploaded successfully`);
      } else if (info.file.status === 'error') {
        message.error(`${info.file.name} file upload failed.`);
      }
    },
    onRemove(file) {
      const promise: PromiseLike<void | boolean> = deleteArtifact({ filename: file.response });
      promise.then((value: any) => {
        if (value === '' || value instanceof Response && value.status === 205) {
          const index = fileList.indexOf(file);
          const newFileList = fileList.slice();
          newFileList.splice(index, 1);
          setFileList(newFileList);
        }
      });
    },
  };

  return (
    <Modal
      destroyOnClose
      title='上传归档文件'
      visible={visible}
      onCancel={onCancel}
    >
      <Upload
        {...uploadProps}
      >
        <Button>
          <UploadOutlined/> Click to Upload
        </Button>
      </Upload>
    </Modal>
  );
};

export default UploadModal;

@codepandy
Copy link

@codepandy codepandy commented Apr 20, 2020

好坑啊,uploading状态必须设置fileList不然,只执行一次,折腾半天,无语死了。

@SaiRO97
Copy link

@SaiRO97 SaiRO97 commented Apr 23, 2020

I post a successful case for your reference. I've had this problem before, though. Also calculate here make a note, in order to facilitate oneself forgot convenient search later

env:

  • antd: 4.0.0-rc.1
  • pro-layout: 5.0.0
  • react: 16.9.17
import React, { useState } from 'react';
import { Modal, Upload, Button, message } from 'antd';
import { UploadOutlined } from '@ant-design/icons/lib';
import { UploadProps } from 'antd/lib/upload';
import { deleteArtifact } from '@/services/artifact';

interface UploadModalType {
  visible: boolean
  onCancel: () => void
  projectId: number
}

const UploadModal: React.FC<UploadModalType> = props => {
  const { visible, onCancel, projectId } = props;
  const [fileList, setFileList] = useState();

  const uploadProps: UploadProps = {
    name: 'file',
    fileList,
    listType: 'text',
    action: 'http://localhost:8080/v1/artifacts',
    data: { project_id: projectId, type: 'application/json' },
    onChange(info) {

      setFileList(info.fileList.slice()); // Note: A new object must be used here!!!

      if (info.file.status === 'done') {
        message.success(`${info.file.name} file uploaded successfully`);
      } else if (info.file.status === 'error') {
        message.error(`${info.file.name} file upload failed.`);
      }
    },
    onRemove(file) {
      const promise: PromiseLike<void | boolean> = deleteArtifact({ filename: file.response });
      promise.then((value: any) => {
        if (value === '' || value instanceof Response && value.status === 205) {
          const index = fileList.indexOf(file);
          const newFileList = fileList.slice();
          newFileList.splice(index, 1);
          setFileList(newFileList);
        }
      });
    },
  };

  return (
    <Modal
      destroyOnClose
      title='上传归档文件'
      visible={visible}
      onCancel={onCancel}
    >
      <Upload
        {...uploadProps}
      >
        <Button>
          <UploadOutlined/> Click to Upload
        </Button>
      </Upload>
    </Modal>
  );
};

export default UploadModal;

I have the same problem using Func component. Info.status always has uploading status and onChange calls only once

@SCLGIS
Copy link

@SCLGIS SCLGIS commented Jul 14, 2020

@tsuijie 3.13.5 已修复。

3.13.5 我也出现了同样的问题 onChange中操作this.setState({fileList})会导致上传请求被取消

@suedar
Copy link

@suedar suedar commented Jul 26, 2020

如果没有使用其action接口,在上传后会出现一直上传中的状态,需要手动将每个文件的status设置为done

@yoyo837
Copy link
Contributor

@yoyo837 yoyo837 commented Jul 26, 2020

如果没有使用其action接口,在上传后会出现一直上传中的状态,需要手动将每个文件的status设置为done

请检查fileList回写state时有没有使用新对象,[...fileList]

@SCLGIS
Copy link

@SCLGIS SCLGIS commented Jul 26, 2020

@rodrigoclp
Copy link

@rodrigoclp rodrigoclp commented Aug 25, 2020

It doesn't work if I use hooks with the "multiples" options enabled.
If I select 3 files, I get 2 on the list. If I select 5 files, I get only 3, sometimes 4. If I remove the prop "fileList", it works fine, and I can see all the files on the list, but I can't control them - I need to use the "fileList" prop.
I have a different behavior if I use class component instead of the hook useState.

@hope0922
Copy link

@hope0922 hope0922 commented Aug 28, 2020

在4.5.1上也遇到这个问题,一直是uploading的状态。试了前面大佬说的方法都没用,最后看了源码发现是因为我render时每次的upload组件的key值不一样,导致重新渲染了,源码默认就取消了前面的上传请求,导致一直是uploding的状态,key值固定然后就正常可以上传成功了

@tsuijie 3.13.5 已修复。

3.13.5 我也出现了同样的问题 onChange中操作this.setState({fileList})会导致上传请求被取消

@yoyo837
Copy link
Contributor

@yoyo837 yoyo837 commented Jan 13, 2021

有种情况就是这样的 怎么解决 fileList 并不能直接修改
image

这样试试 #28827 (comment)

@sherfruit
Copy link

@sherfruit sherfruit commented Jan 13, 2021

有种情况就是这样的 怎么解决 fileList 并不能直接修改
image

这样试试 #28827 (comment)

谢谢 已经解决了!

@dulara1994
Copy link

@dulara1994 dulara1994 commented Feb 7, 2021

I understand nothing, all chineese.

@lovetoburnswhen
Copy link

@lovetoburnswhen lovetoburnswhen commented Feb 23, 2021

I understand nothing, all chineese.

google translate is your friend ;)

@YRNH
Copy link

@YRNH YRNH commented Apr 6, 2021

I understand nothing, all chinees
u should setState first

@WLyKan
Copy link
Contributor

@WLyKan WLyKan commented Apr 28, 2021

我没有使用 fileList 属性,应该不是受控模式,在 status === 'uploading'的判断分支中使用了setState,也导致上传不发请求,onchange自调用一次的问题。

@afc163
Copy link
Member

@afc163 afc163 commented Apr 28, 2021

@WLyKan 升级到最新版本试试?

@qidaneix
Copy link

@qidaneix qidaneix commented Jun 8, 2021

这里的api设计实属奇怪,onChange需要setFileList,但onRemove却不需要

@quyuxuan
Copy link

@quyuxuan quyuxuan commented Jun 9, 2021

使用4.16.2 版本的upload 同样只能触发一次onChange

@max8hine
Copy link

@max8hine max8hine commented Jun 9, 2021

My solution is to use the ref prop on the Upload component to trigger the onChange event when the data sources from outside of the Upload component, such as the paste event or global states.

And then, the external data source files = [] could be passed down to uploadFiles method like example code below, the method will trigger all internal life cycles, including the onChange event. Additionally combining with the full controlled state fashion #2423 (comment) by @afc163, it works well for me in antd@4.16.2

the fastforward ref and upload.uploader.uploadFiles method could not be found in documents. therefore, I am not sure whether it's safe to use or not.

Example code with external data source from the paste event

import { useRef } from "react";
import { Upload } from "antd";

function MyComponent(props) {
  const ref = useRef(null);
  const onPaste = (event) => {
    if (event.clipboardData.files.length > 0) {
	  // My solution, but any better idea?
      refUpload.current.upload.uploader.uploadFiles(event.clipboardData.files);
    }
  };
  useEffect(() => {
    window.addEventListener("paste", onPaste);
    return () => {
      window.removeEventListener("paste", onPaste);
    };
  }, []);
  return <Upload {...props} ref={ref} />
}

Solution from this part of the source code

@ar7casper
Copy link

@ar7casper ar7casper commented Jun 15, 2021

Any news on that?
First time I upload a file, I get info.file.status==='done'.
Then, I remove.
When I upload a new file, I get info.file.status==='uploading' and it doesn't change.

@max8hine
Copy link

@max8hine max8hine commented Jun 15, 2021

Any news on that?
First time I upload a file, I get info.file.status==='done'.
Then, I remove.
When I upload a new file, I get info.file.status==='uploading' and it doesn't change.

@ar7casper Please check this #2423 (comment), and the last bit of the Chinese part is the key

注意需要克隆 fileList 以保障 Upload 能感知数组变化
Please clone fileList to ensure Upload can feel the changes of the array(fileList)

And please update your controlled fileList in every cycle. more specifically, did you update fileList in the uploading cycle? If not, the uploading cycle won't trigger the done cycle

@huaiguoguo
Copy link

@huaiguoguo huaiguoguo commented Jun 18, 2021

对于受控模式,你应该在 onChange 中始终 setState fileList,保证所有状态同步到 Upload 内。类似这里的写法:http://ant.design/components/upload/#components-upload-demo-fileList

// good

onFileChange(fileList) {
  if ( ... ) {
    ...
  } else {
    ...
  }
  // always setState
  this.setState({ fileList: [...fileList] });
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />
// bad

onFileChange(fileList) {
  if ( ... ) {
    this.setState({ fileList: [...fileList] });
  } else {
    ...
  }
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />

建议研习受控组件概念:https://facebook.github.io/react/docs/forms.html#controlled-components

注意需要克隆 fileList 以保障 Upload 能感知数组变化。

- this.setState({ fileList });
+ this.setState({ fileList: [...fileList] });

very thanks,
i am try this , is works
thanks again....

@nmsn
Copy link

@nmsn nmsn commented Sep 10, 2021

对于受控模式,你应该在 onChange 中始终 setState fileList,保证所有状态同步到 Upload 内。类似这里的写法:http://ant.design/components/upload/#components-upload-demo-fileList

// good

onFileChange(fileList) {
  if ( ... ) {
    ...
  } else {
    ...
  }
  // always setState
  this.setState({ fileList: [...fileList] });
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />
// bad

onFileChange(fileList) {
  if ( ... ) {
    this.setState({ fileList: [...fileList] });
  } else {
    ...
  }
}

...

<Upload fileList={this.state.fileList} onChange={this.onFileChange} />

建议研习受控组件概念:https://facebook.github.io/react/docs/forms.html#controlled-components

注意需要克隆 fileList 以保障 Upload 能感知数组变化。

- this.setState({ fileList });
+ this.setState({ fileList: [...fileList] });

如果我想 Upload 受控的情况下, 被 form 获取到的数据 和 Upload 内部维护的不一样该如何处理

@nyanboard
Copy link

@nyanboard nyanboard commented Sep 30, 2021

官网demo是不是有点问题,

{fileList.length >= 8 ? null : uploadButton}

官网例子fileList.length >=8 的时候会隐藏上传按钮,但是现在上传组件需要在onchange方法中执行this.setState({ fileList }
那么问题就来了,图片在上传过程中(文件状态为上传中,不是已完成),会触发onchange方法,这样导致fileList的长度改变,重新渲染render,导致上传接口被canceled

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet