Skip to content

Instantly share code, notes, and snippets.

@dohomi
Last active August 5, 2021 08:31
Show Gist options
  • Save dohomi/78d240028a3450c5477e91e6004288ab to your computer and use it in GitHub Desktop.
Save dohomi/78d240028a3450c5477e91e6004288ab to your computer and use it in GitHub Desktop.
File Upload with firebase and React as a hook and example use with useDropzone
// example usage with useDropzone
const FileUpload:FC = ({onUploaded}) => {
const [user] = useUser()
const [uploadFiles, { error, loading }] = useUploadFiles()
const onDrop = useCallback(
async (acceptedFiles: File[], rejections?: FileRejection[]) => {
if (rejections?.length) {
console.error(rejections)
} else {
await uploadFiles(acceptedFiles, {
filePrefix: `${user.uid}/${Date.now()}/`,
onUploaded
})
}
},
[onUploaded, uploadFiles]
)
const { getRootProps, getInputProps } = useDropzone({
onDrop,
accept: 'application/pdf'
})
return (
<>
<input {...getInputProps()} />
<div {...getRootProps()} />
</>
}
}
import { useMemo, useState } from 'react'
import 'firebase/storage'
import firebase from 'firebase/app'
type UploadFilePayload = {
path: string
name: string
type: string
size: number
}
const uploadFile = async ({
blobUrl,
name,
type,
size
}: {
blobUrl: string
name: string
type: string
size: number
}): Promise<UploadFilePayload> => {
if (!blobUrl || !name) return null
const blob = await fetch(blobUrl).then((r) => r.blob())
const snapshot = await firebase.storage().ref().child(name).put(blob)
const path = await snapshot.ref.fullPath
return {
name,
path,
type,
size
}
}
type UploadFilesOptionsProps = {
filePrefix?: string
onUploaded?: (files: UploadFilePayload[]) => Promise<void>
}
const useLmUploadFiles = (): [
(
files: File[],
options?: UploadFilesOptionsProps
) => Promise<UploadFilePayload[]>,
{
error: firebase.FirebaseError
loading: boolean
files: UploadFilePayload[] | undefined
}
] => {
const [error, setError] = useState<firebase.FirebaseError>()
const [files, setFiles] = useState<UploadFilePayload[] | undefined>()
const [loading, setLoading] = useState<boolean>(false)
const uploadFiles = async (
filesToUpload: File[],
{ filePrefix, onUploaded }: UploadFilesOptionsProps
): Promise<UploadFilePayload[]> => {
setLoading(true)
try {
const downloadUrls: Promise<UploadFilePayload>[] = []
Array.from(filesToUpload).forEach((file) => {
const fileName = `${filePrefix || ''}${file.name}`
downloadUrls.push(
uploadFile({
type: file.type,
size: file.size,
blobUrl: URL.createObjectURL(file),
name: fileName
})
)
})
const allFiles = await Promise.all(downloadUrls)
if (typeof onUploaded === 'function') {
await onUploaded(allFiles)
}
setFiles(allFiles)
setLoading(false)
return allFiles
} catch (e) {
setError(e)
setLoading(false)
return []
}
}
const memoized = useMemo(() => {
return { files, error, loading }
}, [files, error, loading])
return [uploadFiles, memoized]
}
export default useLmUploadFiles
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment