0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ant design - Upload コンポーネントでファイルをローカルファイルとして扱いたい

Last updated at Posted at 2025-04-27

antDesignはフロントエンドにおけるデザインシステムの一つで、最近業務アプリケーション開発で結構利用させていただいています。

使い勝手も良く重宝しているのですが、ファイルアップロードで利用するUploadにて、「ローカル(ブラウザ)にファイルを保存しておき、submitボタンを押してバックエンドに送信する」ということの実現で少し困りました。

というのも、ファイル添付時、Uploadコンポーネントはデフォルトで、設定したULRにファイルを転送するという機構になっています。

それを設定しない or 適当なurlを設定しておくなどで良さそうかと思ったのですが、リクエスト結果に応じてファイルアップロードが正常に完了した / 完了しなかった というステータスを持つため、ローカルにファイルはあるものの、画面上はアップロードに失敗したような状態となってしまいます。

備忘録として、その一つの対処法を記載します。

参考記事:

実装

少し量が多かったため、適当なフックを作成しています。
また、テストプロジェクトを作成し、最初のコンポーネント(App.tsx)にuploadを配置した形です。
後ほど少し解説しますが、ひとまず全体像です。

use-upload-file.ts
import { UploadFile, UploadProps, message } from 'antd'
import { useEffect, useState } from 'react'

export const useUploadFile = () => {
  const [fileList, setFileList] = useState<UploadFile[]>([])

  useEffect(() => {
    console.log('File list updated:', fileList)
  })

  const handleFileChange: UploadProps['onChange'] = (info) => {
    if (info.file.status !== 'uploading') {
      console.log(info.file, info.fileList)
    }

    if (info.file.status === 'done') {
      setFileList(info.fileList)
      message.success(`${info.file.name} file uploaded successfully`)
    } else if (info.file.status === 'error') {
      message.error(`${info.file.name} file upload failed.`)
    } else {
      setFileList(info.fileList)
    }
  }

  return { handleFileChange, fileList }
}
App.tsx
import { Button, Upload, UploadProps } from 'antd'
import { useUploadFile } from './-hooks/use-upload-file'
import { UploadOutlined } from '@ant-design/icons';
import './App.css'
import React from 'react'

function App() {
  const { handleFileChange, fileList } = useUploadFile()
  const props: UploadProps = {
    name: 'test',
    onChange: handleFileChange,
    maxCount: 1,
    // beforeUploadにfalseを返す関数を渡す
    beforeUpload: (() => false)
  }
  const handleSubmit = async () => {
    try {
      // ファイル送信メソッドなど
      console.log(fileList[0])
    } catch (e) {
      console.log(e)
    }
  }

  return (
    <div>
      <Upload {...props} fileList={fileList}>
        <Button icon={<UploadOutlined />}>Click to Upload</Button>
      </Upload>
      <Button onClick={handleSubmit}>submit</Button>
    </div>
  )
}

export default App

結果:
ファイルアップロードは正常に完了した表示になり、onSubmitで値が取れていることが確認できます。
(orginFileObjにファイルオブジェクトが入っています。)

image.png

ポイント

beforeUploadに、falseを返す関数を渡したことです。
公式の説明をみると、beforeUploadの説明は以下のようになっています。

Hook function which will be executed before uploading. Uploading will be stopped with false or a rejected Promise returned. When returned value is Upload.LIST_IGNORE, the list of files that have been uploaded will ignore it. Warning:this function is not supported in IE9

この、falseの場合アップロード処理が止まるというところを利用している感じですね。

Uploading will be stopped with false

ただ、FileListにはファイルが保存されているので、submitで送信などで扱うことができます。
useStateなどでファイルリストを管理すると、その後の操作がよりやりやすいのかなと思います。

余談

ここからは本当に余談ですが、最初は以下のような実装をしていました。

// ダミーリクエスト関数を作成
// (antd - uploadの)onSuccessを受け取り、okを返す
export const dummyRequest = (options: { onSuccess?: (response: unknown) => void }) => {
  const { onSuccess } = options
  setTimeout(() => {
    if (onSuccess) {
      onSuccess('ok')
    }
  }, 0)
}

// Uploadに渡すPropsのcustomRequestに上記関数を設定
  const props: UploadProps = {
    name: 'test',
    onChange: handleFileChange,
    maxCount: 1,
    customRequest: dummyRequest
  }

参考にしていたstackOverflowの記事では、最初にこちらの解決方法が記載されており、それをtypeScript verにしたものです。

こちらは、upload url等を渡さないため、外部へのアップロードは起こらない。その後、ファイルアップロード成功時のコールバック関数を受け取りダミーのステータスを返すという実装になります。

こちらでも同じような動作を得ることができますが、「単に外部でのアップロードを無しにしたい」というモチベーションの場合、beforeUploadでfalseを返してあげ得る方がシンプルに実装できますね。

※ちゃんと最後までstackOverflowを見ていれば回り道せず済んだかもしれないですが、日本語だとあまり記事が出てこず、英語で記事がヒットしたことで気がはやりました。
結果、より多くの時間をかけてしまったなと反省です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?