- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
本篇文章围绕 rsuite(React Suite)组件库中 Uploader 上传组件的核心数据类型FileType展开,它定义了上传文件在组件内部与对外接口中统一流转的数据结构。读完本文,你将掌握FileType每个字段的类型约束、取值语义与默认行为,理解inited → uploading → finished / error这条上传状态机在源码中的落地方式,并能在受控/非受控、手动上传、队列校验、自定义渲染等真实场景中正确构造和使用该类型。
什么是FileType?
FileType是 rsuite Uploader 中描述「一个待上传或已上传文件」的标准接口。官方类型定义位于 docs/pages/_common/types/file-type.md,并被 Uploader 的文档属性表反复引用(defaultFileList、fileList以及全部上传回调参数都是FileType或FileType[])。
其完整定义如下:
interface FileType { /** File Name */ name?: string; /** File unique identifier */ fileKey?: number | string; /** File upload status */ status?: 'inited' | 'uploading' | 'error' | 'finished'; /** File upload status */ progress?: number; /** The url of the file can be previewed. */ url?: string; }注意:官方文档中status与progress的注释都写成了 "File upload status",但从字段名与源码实现可以确认,前者是文件上传状态,后者是上传进度百分比,属于文档注释上的笔误,本文按实现语义讲解。
字段逐个拆解
name?: string—— 文件名称
用于展示在文件列表项中。在 UploadFileItem.tsx 中,文件名被渲染为列表项标题,并用于预览按钮与删除按钮的aria-label(如Preview: ${file.name})。当用户通过文件选择框选入文件时,Uploader 会自动把原生File.name写入该字段(见 Uploader.tsx):
newFileList.push({ blobFile: file, name: file.name, status: 'inited', fileKey: guid() });fileKey?: number | string—— 文件唯一标识
Uploader 内部以fileKey作为文件的唯一 ID,用于增删改查。从源码看,fileListReducer的remove与updateFile分支都通过fileKey匹配文件(Uploader.tsx):
case 'remove': return files.filter(f => f.fileKey !== action.fileKey); case 'updateFile': return files.map(file => file.fileKey === action.fileKey ? action.file : file );手动构造初始文件列表时,fileKey必须自行提供且保持唯一(通常用数字递增或字符串 ID);若未提供,createFile会用guid()自动生成并给progress归零(Uploader.tsx)。这一行为同时作用于defaultFileList的初始化。
status?: 'inited' | 'uploading' | 'error' | 'finished'—— 上传状态
status是FileType的核心,取值集合在源码中被单独抽出为别名类型FileStatusType(Uploader.tsx):
export type FileStatusType = 'inited' | 'uploading' | 'error' | 'finished';四个状态构成一条完整的上传生命周期:
| 状态 | 语义 | 触发时机(依据源码) |
|---|---|---|
inited | 已入队、尚未开始上传 | 文件被选中加入队列时(handleUploadTriggerChange中默认status: 'inited') |
uploading | 正在上传 | handleUploadFile调用ajaxUpload前立即置为uploading(Uploader.tsx) |
finished | 上传成功 | handleAjaxUploadSuccess将status置为finished、progress置为100(Uploader.tsx) |
error | 上传失败 | handleAjaxUploadError将status置为error(Uploader.tsx) |
status直接驱动列表项的 UI 表现:error时渲染错误文案与「重新上传」按钮(renderErrorStatus)、uploading时显示进度条与 loading 图标(renderProgressBar/renderIcon)、且data-has-error属性由file.status === 'error'决定(UploadFileItem.tsx)。
progress?: number—— 上传进度百分比
取值 0~100,由底层 XHR 的upload.onprogress事件计算得出(ajaxUpload.ts):
if (event.lengthComputable) { percent = (event.loaded / event.total) * 100; } onProgress?.(percent, event, xhr);handleAjaxUploadProgress会把百分比写回文件对象并同步触发onProgress回调(Uploader.tsx);列表项中的进度条宽度即为progress%(UploadFileItem.tsx)。新入队文件的初始progress为 0,成功时为 100。
url?: string—— 可预览的文件地址
对已上传文件(如服务端返回的图片 CDN 地址)提供url即可直接预览;没有url时,Uploader 会尝试对本地blobFile生成缩略图(见下文)。在picture/picture-text列表模式下,url或生成的缩略图会被渲染为<img>(UploadFileItem.tsx)。
接口实现中的隐藏字段:blobFile
官方文档呈现的是精简版接口,仓库源码中的FileType还包含一个被文档省略的字段blobFile(Uploader.tsx):
export interface FileType { name?: string; fileKey?: number | string; /** https://developer.mozilla.org/zh-CN/docs/Web/API/File */ blobFile?: File; status?: 'inited' | 'uploading' | 'error' | 'finished'; progress?: number; url?: string; }blobFile保存浏览器原生File对象,是实际发生上传的数据载体:ajaxUpload直接接收file.blobFile作为请求体(Uploader.tsx)。此外它还有两个派生用途:
- 展示文件大小:
formatSize(file.blobFile.size)将字节数格式化为 KB/MB/GB(UploadFileItem.tsx); - 生成本地预览:
previewFile通过FileReader.readAsDataURL将图片blobFile转成 data URL 作为缩略图(previewFile.ts),但仅当文件大小不超过maxPreviewFileSize(默认 5MB,即 5242880)时生效。
在写代码时,凡是「由用户本地选入的文件」,blobFile都由 Uploader 自动填充,你只需消费FileType其他字段即可。
FileType在实操场景中的用法
场景一:初始化已上传文件列表(defaultFileList/fileList)
官方示例 file-list.md 展示了如何用FileType[]预置文件列表——只提供name、fileKey、url三个字段即可实现「图片缩略图 + 预览 + 删除」:
import { Uploader, Button } from 'rsuite'; const fileList = [ { name: 'A puppy sleeping on its belly', fileKey: 1, url: 'https://images.unsplash.com/photo-1583512603805-3cc6b41f3edb?w=265' }, { name: 'A puppy looking at me with big eyes', fileKey: 2, url: 'https://images.unsplash.com/photo-1561037404-61cd46aa615b?w=300' } ]; const App = () => ( <Uploader listType="picture-text" defaultFileList={fileList} action="//jsonplaceholder.typicode.com/posts/" > <Button>Select files...</Button> </Uploader> );两者的区别:defaultFileList是非受控初始值,仅用于首次渲染;fileList是受控数据源。当传入受控fileList时,Uploader 会在其变化时通过dispatch({ type: 'init', files: fileListProp })强制同步内部队列(Uploader.tsx),并尽量保留已有文件的状态(Uploader.tsx)。受控写法的官方示例 controlled.md:
const App = () => { const [value, setValue] = React.useState([]); return ( <Uploader fileList={value} action="//jsonplaceholder.typicode.com/posts/" onChange={setValue}> <Button>Select files...</Button> </Uploader> ); };场景二:手动触发上传(autoUpload={false}+ 实例方法start)
设置autoUpload={false}后,选中的文件只以status: 'inited'进入队列而不发起请求,随后通过ref调用实例的start()方法批量上传(manually.md):
const uploader = React.useRef(); <Uploader fileList={fileList} autoUpload={false} action="//jsonplaceholder.typicode.com/posts/" onChange={setFileList} ref={uploader} > <Button>Select files...</Button> </Uploader> <Button disabled={!fileList.length} onClick={() => uploader.current.start()}> Start Upload </Button>start()是UploaderInstance暴露的公共 API(Uploader.tsx):传入单个FileType则只上传该文件,不传则遍历队列中status === 'inited'的文件逐个上传(Uploader.tsx)。
场景三:上传前校验(shouldQueueUpdate/shouldUpload)
这两个回调的入参都是FileType及其数组,返回boolean或Promise<boolean>,分别用于「文件加入队列前」与「文件上传前」的校验(官方示例 check.md):
<Uploader action="//jsonplaceholder.typicode.com/posts/" shouldQueueUpdate={fileList => { // 返回 false 则不更新队列;也可返回 Promise 做异步校验 return true; }} shouldUpload={file => { // 返回 false 则跳过该文件的上传 return true; }} > <Button>Select files...</Button> </Uploader>从源码看,shouldQueueUpdate返回false时,Uploader 会清空 input 且不加入队列(Uploader.tsx);shouldUpload的判定发生在handleAjaxUpload遍历队列时,同样支持同步布尔与Promise(Uploader.tsx)。
场景四:在回调与自定义渲染中消费FileType
Uploader 的全部上传回调(onChange、onSuccess、onError、onProgress、onPreview、onRemove、onReupload、onCompletion、onUpload)的file参数类型均为FileType。其中onCompletion(completedFiles, failedFiles)会在当前批次全部上传结束后,分别给出成功与失败的文件数组(Uploader.tsx)。类型层面的校验可参考 Uploader.test.tsx 中的expectType断言。
自定义渲染同样接收FileType:renderFileInfo/renderThumbnail的签名分别为(file: FileType, fileElement: ReactNode) => ReactNode。官方示例 file-list-custom.md 中通过file.url展示自定义文件信息;若在服务端返回额外字段(如上传人、日期),可扩展FileType的子类型或直接复用renderFileInfo读取这些自定义字段——Uploader 内部对未知字段不做丢弃处理。
上传请求层如何配合FileType
理解FileType的流转闭环离不开底层的ajaxUpload(ajaxUpload.ts)。Uploader 将FileType中的blobFile与组件级配置(name、method、data、headers、timeout、withCredentials、disableMultipart)打包成一次XMLHttpRequest:
- 默认以
multipart/form-data方式发送,name(默认'file')作为文件字段名,data作为附加表单参数; - 设置
disableMultipart后改为直接流式发送File本体,适用于 Amazon S3 等期望裸文件流的上传接口; - 响应按 2xx 判定成功,成功/失败/超时分别映射回
finished/error状态并回写FileType,从而驱动列表 UI 与回调。
小结
FileType是 rsuite Uploader 贯穿「选文件 → 入队 → 校验 → 上传 → 完成/失败 → 展示与删除」全流程的统一数据模型:
- 状态字段
status与进度字段progress组成了文件的状态机,UI 完全由状态驱动; - 标识字段
fileKey支撑队列的增删改查,缺失时由内部guid()补全; - 预览字段
url与隐藏的blobFile分别支撑服务端文件展示与本地缩略图生成; - 该类型同时是非受控
defaultFileList、受控fileList以及十余个回调函数的统一入参,是二次开发、类型扩展与表单校验时最需要掌握的接口。
在基于 rsuite 封装上传业务时,建议直接以FileType为基础声明业务子类型(例如interface AttachmentFile extends FileType { id: string; uploadedBy?: string }),即可在保持与 Uploader 全部接口兼容的前提下自由扩展业务字段。
- 前端
- UI组件
【免费下载链接】rsuite
🧱 A suite of React components .
相关推荐
Redux Thunk与文件上传验证:类型与大小状态
Redux Thunk与文件上传验证:类型与大小状态 你还在为文件上传时的类型错误和大小超限头疼吗?是否遇到过用户上传GB级文件导致服务器崩溃的情况?本文将通过
前端TanStack Form BroadcastFormState 类型详解:DevTools 表单状态广播机制的类型契约
TanStack Form BroadcastFormState 类型详解:DevTools 表单状态广播机制的类型契约 BroadcastFormState
前端UI组件探索高效文件类型识别:filetype 库
探索高效文件类型识别:filetype 库 在数据处理和文件管理中,正确识别文件类型是一个至关重要的任务。今天,我们将深入探讨一个强大的开源库 —— ,它为开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考