記一筆之:antd 的 Upload 上傳組件 uploading 狀態(tài)踩坑記

相信用 Upload 的很多老兄都遇到過(guò)這個(gè)問(wèn)題,就是在處理上傳文件時(shí)缀棍,從 onchange 方法中得到的 e.fileList 里面的 status 參數(shù)他么總是 uploading 熟嫩,而不是我們需要的 done 狀態(tài)秦踪,導(dǎo)致拿不到 thumbUrl 和 response 的 imgUrl 。
根據(jù)官網(wǎng)文檔上對(duì) 這個(gè)問(wèn)題 的解釋掸茅,就是要注意兩點(diǎn):

  • 其一是要保證 onchange 事件內(nèi)部椅邓,至少有一次無(wú)阻礙的調(diào)用 setState 賦值 fileList,讓所有狀態(tài)變化都及時(shí)更新昧狮。當(dāng)然這個(gè)“無(wú)阻礙”是我自己的理解景馁,就是說(shuō) setState 的方法執(zhí)行最好不寫在 if 這類條件判斷里面,直接寫在最底部或者最頂部就行逗鸣;
  • 其二是要保證每次 setState 后 fileList 的狀態(tài)都是最新的合住。所以,以上 issue 里面建議上一點(diǎn)我說(shuō)的寫法最好是:
 this.setState({ fileList: [...this.state.fileList] })

不過(guò)對(duì)于以上第二點(diǎn)撒璧,個(gè)人親測(cè)透葛,即使直接 { fileList: e.fileList } 就可以。以下假定只傳一張圖片卿樱,一個(gè)完整的 onchange 事件內(nèi)部處理可以像下面一樣:

handleChange = e => {
    if (e.file.status == 'done') {
      if (e.file.response.code === 200) {
        let result = e.fileList;
        result[0].thumbUrl = result[0].response.imgUrl; //用絕對(duì)路徑替代base64僚害,有助于在保存圖片的時(shí)候避免字段過(guò)長(zhǎng)和減小數(shù)據(jù)庫(kù)的壓力
        this.setState({ fileList: result });
      } else {
        Modal.warn({
          title: '提示',
          content: <span>{e.file.response.msg}</span>,
          okText: 'ok',
        });
      }
    }
    this.setState({ fileList: e.fileList });
  };

對(duì)應(yīng)的react DOM結(jié)構(gòu)可以是:

          <FormItem label="上傳圖片">
                {this.props.form.getFieldDecorator('file', { rules: [{ required: true, message: '請(qǐng)上傳圖片' }] })(
                    <div>
                      <Upload
                        name="file"
                        multiple={false}
                        headers={{ Accept: 'application/json', token: getToken() }}
                        action={this.state.imgUploadUrl}
                        listType="picture-card"
                        fileList={this.state.fileList}
                        onPreview={this.handlePreview}
                        onChange={this.handleChange}
                        accept="image/jpg, image/png"
                      >
                        {this.state.fileList.length >= 1 ? null : <div><Icon type="plus" /><div className="ant-upload-text">上傳</div></div>}
                      </Upload>
                      <Modal visible={this.state.previewVisible} footer={null} onCancel={this.handleCancel}>
                        <img alt="example" style={{ width: '100%' }} src={this.state.previewImage} />
                      </Modal>
                    </div>
                )}
              </FormItem>

如上DOM結(jié)構(gòu),在一些常規(guī)操作中繁调,上傳圖片的操作萨蚕,很可能會(huì)存在這樣的場(chǎng)景:新建記錄靶草、更新記錄、獲取記錄詳情门岔、保存記錄等等爱致,同時(shí)配合使用 Form 以及 Form.Item 組件,以及 getFieldValue寒随、setFieldValue糠悯、getFieldDecorator 等等 api 使 Upload 的操作受控。在使用 Upload 組件時(shí)妻往,也許需要注意以下幾點(diǎn):

  • 其一:在獲取記錄詳情時(shí)互艾,拿到圖片的 url,一定要將 state 中的 fileList 的 status 狀態(tài)設(shè)為 done:
          this.setState({
              previewImage: url,
              fileList: [ {
                  thumbUrl: url,
                  status: 'done',    // 這個(gè)必須讯泣,不然纫普,圖片自然顯示不出來(lái)
                  uid: url,      // 這個(gè)隨意吧
              } ],
            });
      // 以及將受控字段的值設(shè)為 url:
        this.props.form.setFieldsValue( { file: bannerUrl } )
  • 其二:在編輯圖片的時(shí)候,比如想將圖片替換掉好渠,這兒在提交的時(shí)候昨稼,就要注意一下,看代碼:
handleAddSubmit = () => {
    const { form: { validateFields, setFieldsValue } } = this.props;
    const { fileList } = this.state;
    if (!fileList.length) {
      // 編輯圖片時(shí)候拳锚,如果刪掉縮略圖假栓,fileList會(huì)被清空,不過(guò) getFieldsValue 獲取file 的值還在霍掺,這時(shí)候提交無(wú)errors匾荆,但是fileList是空的
      setFieldsValue({ file: undefined });
    }
    validateFields((errors, values) => {
      if (!errors) {
        let data = {
          url: fileList[0].thumbUrl,
        }
       // 以下做你的騷操作。杆烁。牙丽。
     }
 }
圖片1.png

以上代碼有一句注釋,說(shuō)啥意思呢兔魂?意思就是烤芦,我們?cè)诰庉媹D片的時(shí)候,可能想把圖片換一張析校,就刪掉了构罗,然而,這個(gè)時(shí)候打了一秒鐘瞌睡勺良,醒來(lái)就搞忘了,就直接點(diǎn)提交骄噪。這個(gè)時(shí)候呢尚困,本來(lái) Form 組件在使用 getFieldDecorator 時(shí),已經(jīng)設(shè)置必填了链蕊,然而圖片這個(gè)時(shí)候雖然看似刪掉了事甜,因?yàn)橐陨鲜纠龍D片處已經(jīng)變成一個(gè)上傳提示按鈕了谬泌,但是提交事件雖然沒(méi)有提示以上 errors錯(cuò)誤,但是 thumbUrl 卻報(bào)錯(cuò) undefined 了逻谦?這特么就尷尬了掌实。
這啥原因呢?原因就是 validateFields 的函數(shù)參數(shù) 的values 參數(shù)中邦马,file 字段的值(就是被刪掉的圖片的地址)并沒(méi)有隨著點(diǎn)擊示例圖上刪除那樣贱鼻,把 file 字段的值重置,刪除圖片的操作只是把 fileList 狀態(tài)重置清空了滋将。這個(gè)時(shí)候提交結(jié)果是邻悬,F(xiàn)orm.Item 處并沒(méi)有 必填的錯(cuò)誤提示,validateFields 通過(guò)了必填驗(yàn)證随闽,然而父丰,fileList 早已經(jīng)變成了空數(shù)組。this.props.form.getFieldValue('file') 也就是上一張圖的路徑卻還在掘宪。
所以蛾扇,在操作這種情況時(shí),要判斷 fileList 是否為空魏滚,如果為空表示圖片已經(jīng)被刪除镀首,那么同時(shí)將 file 的狀態(tài)同步一下,做了這個(gè)操作后栏赴,validateFields 驗(yàn)證空?qǐng)D片的時(shí)候蘑斧,就會(huì)有錯(cuò)誤提示“請(qǐng)上傳圖片”。

  • 其三:這是個(gè)有點(diǎn)詭異的卻又可能出現(xiàn)的须眷,那就是竖瘾,你可能已經(jīng)以最規(guī)范的方式,操作了 Upload 組件花颗,但是捕传,onchange 事件中,e.file.status 死活都是 "uploading"扩劝,硬不給你 "done"庸论,你說(shuō)氣人不?
    這個(gè)時(shí)候棒呛,你就要看看聂示,你的組件的 DOM 是否 持續(xù) render 了。為啥這么說(shuō)呢簇秒?因?yàn)橛愫恚钌厦嬉呀?jīng)說(shuō)了,你要保證每次 setState 后 fileList 的狀態(tài)都是最新的,雖然你 Upload 操作很規(guī)范扛禽,但是锋边,fileList 的變化沒(méi)法讓 DOM 節(jié)點(diǎn)及時(shí)渲染,這個(gè)數(shù)據(jù)流的過(guò)程因?yàn)槟愕?DOM 或操作過(guò) React 生命周期等等因素编曼,沒(méi)法及時(shí)反映到 DOM 渲染上豆巨。比如你 shouldComponentUpdate 那兒邏輯是不是有問(wèn)題?封裝組件的時(shí)候掐场,哪兒忘了 fileList 是個(gè)引用類型往扔,沒(méi)有深層比較,或者因?yàn)槠渌蚩桃蓿M件根本就不能觸發(fā) render瓤球。
    收工!
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末敏弃,一起剝皮案震驚了整個(gè)濱河市卦羡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌麦到,老刑警劉巖绿饵,帶你破解...
    沈念sama閱讀 222,183評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瓶颠,居然都是意外死亡拟赊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,850評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門粹淋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)吸祟,“玉大人,你說(shuō)我怎么就攤上這事桃移∥葚埃” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,766評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵借杰,是天一觀的道長(zhǎng)过吻。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蔗衡,這世上最難降的妖魔是什么纤虽? 我笑而不...
    開(kāi)封第一講書人閱讀 59,854評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮绞惦,結(jié)果婚禮上逼纸,老公的妹妹穿的比我還像新娘。我一直安慰自己济蝉,他們只是感情好杰刽,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,871評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布呻纹。 她就那樣靜靜地躺著,像睡著了一般专缠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上淑仆,一...
    開(kāi)封第一講書人閱讀 52,457評(píng)論 1 311
  • 那天涝婉,我揣著相機(jī)與錄音,去河邊找鬼蔗怠。 笑死墩弯,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的寞射。 我是一名探鬼主播渔工,決...
    沈念sama閱讀 40,999評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼桥温!你這毒婦竟也來(lái)了引矩?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,914評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤侵浸,失蹤者是張志新(化名)和其女友劉穎旺韭,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體掏觉,經(jīng)...
    沈念sama閱讀 46,465評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡区端,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,543評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了澳腹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片织盼。...
    茶點(diǎn)故事閱讀 40,675評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖酱塔,靈堂內(nèi)的尸體忽然破棺而出沥邻,到底是詐尸還是另有隱情,我是刑警寧澤延旧,帶...
    沈念sama閱讀 36,354評(píng)論 5 351
  • 正文 年R本政府宣布谋国,位于F島的核電站,受9級(jí)特大地震影響迁沫,放射性物質(zhì)發(fā)生泄漏芦瘾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,029評(píng)論 3 335
  • 文/蒙蒙 一集畅、第九天 我趴在偏房一處隱蔽的房頂上張望近弟。 院中可真熱鬧,春花似錦挺智、人聲如沸祷愉。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,514評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)二鳄。三九已至赴涵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間订讼,已是汗流浹背髓窜。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,616評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留欺殿,地道東北人寄纵。 一個(gè)月前我還...
    沈念sama閱讀 49,091評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像脖苏,于是被迫代替她去往敵國(guó)和親程拭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,685評(píng)論 2 360

推薦閱讀更多精彩內(nèi)容