import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import get from 'lodash/get' import { UploadData, StopUpload, UploadError, UploadFileData, UploadFunction, UploadProgress, UploadStatus } from './types' import { getId } from '../utils' export function useUpload( id: string, name: string, file: File | undefined, status: UploadStatus, onUpload: UploadFunction, handleFileStatusChange: (id: string, status: UploadStatus) => void ): [() => void, boolean, (umount?: boolean) => void, UploadStatus, string, string] { const stopFunction = useRef(undefined) const innerStatus = useRef(status) const [stopStatus, setStopStatus] = useState(false) const [uploadStatus, setUploadStatus] = useState(status) const [progress, setProgress] = useState(null) const [errorInfo, setErrorInfo] = useState('') useEffect(() => { if (innerStatus.current !== uploadStatus) { handleFileStatusChange(id, uploadStatus) innerStatus.current = uploadStatus } }, [handleFileStatusChange, id, uploadStatus]) const onProgress = useCallback((info: UploadProgress) => { setProgress(info) }, []) const onError = useCallback((error: UploadError) => { setUploadStatus('error') // 针对 error 的类型为 any 时可能出现的报错做的兼容性处理 setErrorInfo(get(error, 'message', '')) }, []) const onComplete = useCallback(() => { setUploadStatus('success') }, []) const uploadFile = useCallback(() => { if (!file || innerStatus.current === 'success') return // 等待 onUpload 执行时 stopFunction 未生效 stopFunction.current = undefined setStopStatus(false) setErrorInfo('') setUploadStatus('uploading') stopFunction.current = onUpload(file, { onProgress, onError, onComplete }) setStopStatus(!!stopFunction.current) }, [file, onUpload, onProgress, onError, onComplete]) const stopUpload = useCallback((ummount = false) => { if (stopFunction.current && innerStatus.current === 'uploading') { stopFunction.current() } setProgress(null) // 销毁组件时如果调用 changeStatus 将会不期望地更改 uploadList if (!ummount) { setUploadStatus('stopped') } }, [setUploadStatus]) const percent = useMemo(() => { if (progress?.percent) { return progress.percent.toFixed(2) + '%' } return '0%' }, [progress]) return [uploadFile, stopStatus, stopUpload, uploadStatus, percent, errorInfo] } export function getUploadValue(list: Array): UploadData[] { return list.map(data => { if (typeof data === 'string') { return { id: getId(), name: data, status: 'success' } } return { id: getId(), name: data.name, file: data, status: 'success' } }) } export function isUploadRealFile(data: UploadData): data is UploadFileData { return !!get(data, 'file') }