封裝upload(ant?design)的辛酸史

最近在寫一個OJ網(wǎng)站,里面要用到upload的地方比較多,然后需要對upload進(jìn)行封裝,其中還用到了form,由于遇到了幾個比較隱蔽的問題,而耽誤了幾天,為了讓廣大猿媛們少走彎路,這里講一下自己的封裝過程。

這里提一個比較的需求,就是實(shí)現(xiàn)手動上傳并且獲得上傳后的路徑。

涉及解決的問題

  • 將數(shù)據(jù)返回給父組件

  • 重寫上傳操作,也就是寫customRequest

  • 重寫刪除操作, handleRemove

  • 控制是否顯示上傳列表, showUploadList

  • 用于form

  1. 首先定義存儲數(shù)據(jù)和刷新界面的state和props
constructor(p) {
    super(p);
    this.state = {
      uploadedFileList: [], // 已經(jīng)上傳的文件列表
      // uploadedFilePaths: [] // 已經(jīng)上傳的文件路徑
    };
  }
  static propTypes = {
    showUploadList: PropTypes.bool,
    beforeUpload: PropTypes.func,
    customUpload: PropTypes.func,
    onRemove: PropTypes.func
  }

  static defaultProps = {
    saveType: 'file', // 保存的類型,默認(rèn)為file, 可選的值有 'file','base64','redis'
    fileList: [], // 默認(rèn)的上傳的文件, 格式為 fileList: [{uid: '對應(yīng)文件的uid', name: '文件名稱', status: 'done', url: '文件url'}]
    showUploadList: true, // 是否顯示上傳的文件列表
    onChange: ()=> {}, // 文件值改變的時候的回調(diào)函數(shù)
    // beforeUpload: null, // 文件上傳之前的檢驗(yàn)
    // customUpload: null, // 手動進(jìn)行上傳文件
    // onRemove: ()=> {}, // 成功刪除的回調(diào)函數(shù)
  }

  1. 寫手動上傳的函數(shù)
customUpload= (file) => {
    request.post(`${prefix}/teacher/course/upload`)
      .attach('files', file.file)
      .field({from: 'customUpload'}).then(result=> {
        const uploadedFileList = this.props.value;
        const newFile = {uid: file.file.uid, name: file.file.name, url: result.body.data};
        let fileList = [];
        if (uploadedFileList) {
          uploadedFileList.map((e) => {
            return fileList.push(e);
          });
        }
        fileList.push(newFile);
        this.setState({
          uploadedFileList: [...fileList]
        });

        // 父組件監(jiān)聽數(shù)據(jù)變化
        const {onChange} = this.props;
        onChange(fileList); // 父組件的onChange只會去更改value的值
      });
  }
  1. 寫刪除函數(shù),然后將數(shù)據(jù)變化提交給父組件
handleRemove= (file) => {
  const uploadedFileList = this.state.uploadedFileList.slice();
    const index = uploadedFileList.indexOf(file);
    const [bucket, objectName] = uploadedFileList[index].url.split('/');
    request.delete(`${prefix}/teacher/course/remove`)
      .query({
        bucket,
        objectName
      })
      .then(result => {
        if (result.body.code !== 'SUCCESS') {
          return;
        }
        uploadedFileList.splice(index, 1);
        this.setState({
          uploadedFileList
        });
        // 將數(shù)據(jù)返回給父組件處理
        const {onChange} = this.props;
        let fileList = [];
        uploadedFileList.map((e) => {
          return fileList.push(e);
        });
        onChange(fileList);
      });
}
  1. 將上面的函數(shù)綁定到Upload組件中
         <Upload
          fileList={this.state.uploadedFileList}
          beforeUpload={this.beforeUpload}
          customRequest={this.customUpload}
          onRemove={this.handleRemove}
          // onChange={this.handleChange}
          {...uploadProps}>
          <Button><Icon type='upload'></Icon>上傳文件</Button>
        </Upload>

至此,只需要將這個組件export出去就完成了封裝,比如,我們這個組件叫customUpload,則如下

export default CustomUpload;

上述過程有點(diǎn)看起來很簡單,但是有幾個注意點(diǎn),如下:

  1. uploadcustomRequest不能夠使用async關(guān)鍵字,如果需要向服務(wù)器發(fā)送請求,又想接收返回值做出相應(yīng)操作, 有兩個方式,一個是使用dispatch,一個就是使用.then的方法。如果使用了async關(guān)鍵字,在組件銷毀的時候會報一個reqs[uid].abort的錯誤,需要注意!
  2. 在form組件中,使用的是getFieldDecorator進(jìn)行渲染組件的,這個時候它會往組件中注入value這一個屬性和onChange這個函數(shù)用于存儲值和監(jiān)聽值的改變,所以在封裝的組件中,需要調(diào)用this.props.onChange方法來對希望改變的值進(jìn)行操作。
    以上!希望對大家有所幫助。
    注:上述表述如有錯誤,請各位不吝賜教!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容