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 · 116 comments
Closed

Upload file.status is always being uploading #2423

imxiongying opened this issue Jul 18, 2016 · 116 comments
Labels
❓FAQ issues would be discussed a lot Question Usage

Comments

@imxiongying
Copy link

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 commented Jul 19, 2016

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

@imxiongying
Copy link
Author

@afc163
Copy link
Member

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 commented Oct 11, 2016

e0a986e

@hull123
Copy link

hull123 commented Mar 2, 2017

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

@yifan303
Copy link

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

@yongningfu
Copy link

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

@afc163

@afc163
Copy link
Member

afc163 commented Jun 8, 2017

@yongningfu 感谢提示,已更新。

@TongDaDa
Copy link

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

@bang0929
Copy link

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

@SummerSMJ
Copy link

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 commented Mar 28, 2018

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

@wv1124
Copy link

wv1124 commented Apr 28, 2018

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

@usefire
Copy link

usefire commented May 9, 2018

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

@hope0922
Copy link

在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 commented Jan 13, 2021

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

这样试试 #28827 (comment)

@sherfruit
Copy link

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

这样试试 #28827 (comment)

谢谢 已经解决了!

@dulara1994
Copy link

I understand nothing, all chineese.

@lovetoburnswhen
Copy link

I understand nothing, all chineese.

google translate is your friend ;)

@YRNH
Copy link

YRNH commented Apr 6, 2021

I understand nothing, all chinees
u should setState first

@WLyKan
Copy link
Contributor

WLyKan commented Apr 28, 2021

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

@afc163
Copy link
Member

afc163 commented Apr 28, 2021

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

@qidaneix
Copy link

qidaneix commented Jun 8, 2021

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

@quyuxuan
Copy link

quyuxuan commented Jun 9, 2021

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

@max8hine
Copy link

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 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 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

对于受控模式,你应该在 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 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

官网demo是不是有点问题,

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

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

@mooSylla
Copy link

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

Note that the fileList needs to be cloned to ensure that Upload can sense array changes
Please clone fileListto 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

This fixed it for me thanks

@zuosamu
Copy link

zuosamu commented Jan 25, 2022

怎么关闭加载中的动画呀,好恼火哦,这个东西

@Lancer-xu
Copy link

Lancer-xu commented Mar 4, 2022

这个问题困扰了一个下午,也看了之前留言中的处理方式,主要是围绕新文件数组对象让组件接收数据更新。
最后发现核心点是uploading时的file也需要同样更新到state,这样才能完成可控。

const [fileArr, setFileArr] = useState([]);

setFileArr(fileArr);

uploadProps={
  ...,
  fileArr,
  onChange(info) {
    const fileArr = [];
    info.fileList.forEach((file) => {
    const { status, uid, name, response, url, percent } = file;

    if (status === 'done') {
      fileArr.push({
        uid,
        name,
        status,
        url: response?.responseBody || url,
      });
    } else if (status === 'uploading') {
      fileArr.push({
        uid,
        name,
        status,
        percent,
      });
    }});
  }
}

@hypertextPreprocessor
Copy link

hypertextPreprocessor commented Jun 15, 2022

It seems everybody use react,I also got this issue with antdv (vue3),but I fixed with the following code,hope this can help others:

export const UploadFileCom={
    props:{
        name:{type:String,default:"file"},
        listType:{type:String,default:"picture-card"},
        showUploadList:{type:Boolean,default:false},
        data:{type:Object,default:{bucket:"slide"}}
    },
    emits:['change','beforeUpload','update:fileList'],
    setup(props,{attrs,emit}){
        var store = useConfig();
        var action = `${store.apiHost}/mini/fileUpload/upload`;
        const imageUrl = ref('');
        const loading = ref(false);
        const fileList = ref([]);
        const header = {'Authorization':'bearer '+store.userToken};
        return ()=>h(
            <a-upload
                v-model={[props.fileList,["fileList"]]}
                name={props.name}
                file-list={fileList.value}
                headers={header}
                list-type={props.listType}
                {...attrs}
                show-upload-list={props.showUploadList}
                action={action}
                data={props.data}
                before-upload={(file,flist)=>{
                    emit('beforeUpload',file,flist)
                }}
                onChange={(info)=>{
                    //this is important ,just like setState in react,which mentioned above;
                    fileList.value = info.fileList;
                    emit('update:fileList',info.fileList);
                    if(info.file.status==="uploading"){
                        loading.value = true;
                    }
                    if(info.file.status === 'done'){    
                        var {code,data,msg} = info.file.response;
                        if(code==1){
                            loading.value = false;
                            imageUrl.value = `${store.apiHost}${data.url}`;
                        }else{
                            loading.value = false;
                            message.error(msg);
                        }
                    }
                    if (info.file.status === 'error') {
                        loading.value = false;
                        message.error('upload error');
                      }
                    emit('change',info);
                }}
            >   
                {imageUrl.value!=''?
                    <img style="width:100%;" src={imageUrl.value} />
                :(
                    loading.value?(
                        <LoadingOutlined></LoadingOutlined>
                    ):(
                        <div>
                            <div style="display:block"><PlusOutlined></PlusOutlined></div>
                            <div style="display:block" class="ant-upload-text">上传</div>
                        </div>
                    )
                )}
            </a-upload>
        );
    }
}```

@mib008
Copy link

mib008 commented Jan 23, 2023

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

不自定义customRequest的话,组件默认就会发这个PUT请求上传文件。

  customRequest: (options) => {
    // 设置文件上传状态
    options.onSuccess(null);
  },

@arwebdeveloper
Copy link

arwebdeveloper commented Jan 27, 2023

in below code when I am using fileList prop in with customRequest prop, info.file.status is stuck on "uploading", it never reaches to "done". But when I am using without fileList prop then it's working fine. If there is anybody who can help me with this then it would be a great help.

export default function App() {
  const [fileList, setFileList] = useState([]);
  const [form3] = Form.useForm();
  const onFinishHandler = (values) => {
    console.log("values", values);
  };

  const onUploadChangeHandler = (info) => {
    console.log("onchange", info);
    if (info.file.status === "uploading") {
      console.log("uploading");
    }
    if (info.file.status === "done") {
      console.log("done", info);
      let newArr = [];
      let Location =
        "https://img.freepik.com/free-photo/purple-osteospermum-daisy-flower_1373-16.jpg?w=2000";
      let customFiledata = {
        uid: decodeURI(Location).slice(
          decodeURI(Location).indexOf("uqid") + 5,
          decodeURI(Location).lastIndexOf(".")
        ),
        name: decodeURI(Location).slice(
          decodeURI(Location).indexOf("uqid") + 5
        ),
        status: "done",
        url: Location
      };
      newArr[0] = customFiledata;
      setFileList(newArr);
    } else if (info.file.status === "error") {
      // message.error(`${info.file.name} file upload failed.`);
      console.log("error", info);
    }
  };
  const customRequestHandler = (info) => {
    console.log("customReq", info);
    const { file, onSuccess, onError } = info;
    onSuccess();
  };
  const onclickhandler = () => {
    let newArr = [];
    let Location =
      "https://img.freepik.com/free-photo/purple-osteospermum-daisy-flower_1373-16.jpg?w=2000";
    let customFiledata = {
      uid: decodeURI(Location).slice(
        decodeURI(Location).indexOf("uqid") + 5,
        decodeURI(Location).lastIndexOf(".")
      ),
      name: decodeURI(Location).slice(decodeURI(Location).indexOf("uqid") + 5),
      status: "done",
      url: Location
    };
    newArr[0] = customFiledata;
    console.log("ffffffffffffffff", newArr);
    setFileList(newArr);
  };

  return (
    <div className="App">
      <Form layout="horizontal" form={form3} onFinish={onFinishHandler}>
        <div className="textarea_row">
          <Form.Item label="Passport Photo" name="passport_photo">
            <div>
              <Upload
                multiple={false}
                className="upload-list-inline"
                customRequest={customRequestHandler}
                fileList={fileList}
                maxCount={1}
                onChange={(info) => {
                  onUploadChangeHandler(info);
                }}
              >
                <Button icon={<UploadOutlined />}>Upload</Button>
              </Upload>
            </div>
          </Form.Item>
        </div>
      </Form>
      <Button onClick={onclickhandler}>Onclick</Button>
    </div>
  );
}

@zhuoqinyue
Copy link

zhuoqinyue commented Feb 6, 2023

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

不自定义customRequest的话,组件默认就会发这个PUT请求上传文件。

  customRequest: (options) => {
    // 设置文件上传状态
    options.onSuccess(null);
  },

为什么我自定义customRequest, 且options.onSuccess(url), 但是组件还是一直处于uploading的状态 @mib008

@gudh
Copy link

gudh commented Mar 20, 2023

Well, it's perplexing...

Rather than code snippets, is there any working examples?

Thanks!

@pnd280
Copy link

pnd280 commented Oct 27, 2023

I've noticed that the state passed to fileList is being directly mutated without dispatching, which causes other components that rely on the state not to rerender when the state changes. Any workarounds? To be specific, the thumbUrl property on the info.file object is added after the last onChange call.

@AmanAdastra
Copy link

AmanAdastra commented Nov 27, 2023

If nothing works for you:
Try this: https://gist.github.com/AmanAdastra/59d32c51853843763a80b185ab457933

@605666069
Copy link

605666069 commented Jan 5, 2024

原因是在react 18里面对于所有事件的状态更新进行了批处理,使用flushSync来解决

import { flushSync } from 'react-dom';
const handleChange = ({ fileList }) => {
    flushSync(() => {
      setFileUploadList(fileList);
    });
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
❓FAQ issues would be discussed a lot Question Usage
Projects
None yet
Development

No branches or pull requests