From 3836c59b63186570e843ed0662bb83bf62069530 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 19:59:58 +0300 Subject: [PATCH 01/14] init useDownloadBlob hook --- src/storage/index.ts | 2 ++ src/storage/useDownloadBlob.test.ts | 4 ++++ src/storage/useDownloadBlob.ts | 6 ++++++ 3 files changed, 12 insertions(+) create mode 100644 src/storage/useDownloadBlob.test.ts create mode 100644 src/storage/useDownloadBlob.ts diff --git a/src/storage/index.ts b/src/storage/index.ts index 1c7a03a..7f76c3b 100644 --- a/src/storage/index.ts +++ b/src/storage/index.ts @@ -10,3 +10,5 @@ export * from "./useUploadFileResumable"; export * from "./useDownloadLink"; export * from "./StorageDownloadLink"; + +export * from "./useDownloadBlob"; diff --git a/src/storage/useDownloadBlob.test.ts b/src/storage/useDownloadBlob.test.ts new file mode 100644 index 0000000..576947c --- /dev/null +++ b/src/storage/useDownloadBlob.test.ts @@ -0,0 +1,4 @@ +// Copyright (c) 2024 Eray Erdin +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts new file mode 100644 index 0000000..03564e0 --- /dev/null +++ b/src/storage/useDownloadBlob.ts @@ -0,0 +1,6 @@ +// Copyright (c) 2024 Eray Erdin +// +// This software is released under the MIT License. +// https://opensource.org/licenses/MIT + +export const useDownloadBlob = () => {}; From 8e65095f551ac311e96bd352acd9b34a11fabcc0 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:05:48 +0300 Subject: [PATCH 02/14] test and impl initially, useDownloadBlob hook should have ready state --- src/storage/useDownloadBlob.test.ts | 9 +++++++++ src/storage/useDownloadBlob.ts | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.test.ts b/src/storage/useDownloadBlob.test.ts index 576947c..33a85a9 100644 --- a/src/storage/useDownloadBlob.test.ts +++ b/src/storage/useDownloadBlob.test.ts @@ -2,3 +2,12 @@ // // This software is released under the MIT License. // https://opensource.org/licenses/MIT + +import { renderHook } from "@testing-library/react"; +import { useDownloadBlob } from "."; + +it("initially, useDownloadBlob hook should have ready state", async () => { + const { result } = renderHook(() => useDownloadBlob()); + const { state } = result.current; + expect(state).toBe("ready"); +}); diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 03564e0..3fb5ad9 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -3,4 +3,13 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT -export const useDownloadBlob = () => {}; +type UseDownloadBlobState = "ready"; +type UseDownloadBlob = { + state: UseDownloadBlobState; +}; + +export const useDownloadBlob = (): UseDownloadBlob => { + return { + state: "ready", + }; +}; From 9e6d502b9938cd302b99542bb052479a9bf8933a Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:07:11 +0300 Subject: [PATCH 03/14] wip: add dispatch: UseDownloadBlobDispatcher --- src/storage/useDownloadBlob.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 3fb5ad9..c32e7dc 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -4,12 +4,17 @@ // https://opensource.org/licenses/MIT type UseDownloadBlobState = "ready"; +type UseDownloadBlobDispatcher = () => Promise; type UseDownloadBlob = { state: UseDownloadBlobState; + dispatch: UseDownloadBlobDispatcher; }; export const useDownloadBlob = (): UseDownloadBlob => { return { state: "ready", + dispatch: async () => { + throw "tbi"; + }, }; }; From 58c8d6e60c3ad1cfa2d1a3391cb3c70c229f3124 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:08:03 +0300 Subject: [PATCH 04/14] wip: add UseDownloadBlobParams --- src/storage/useDownloadBlob.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index c32e7dc..73331b5 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -3,6 +3,12 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT +import { StorageReference } from "firebase/storage"; + +type UseDownloadBlobParams = { + reference: StorageReference; +}; + type UseDownloadBlobState = "ready"; type UseDownloadBlobDispatcher = () => Promise; type UseDownloadBlob = { @@ -10,7 +16,9 @@ type UseDownloadBlob = { dispatch: UseDownloadBlobDispatcher; }; -export const useDownloadBlob = (): UseDownloadBlob => { +export const useDownloadBlob = ({ + reference, +}: UseDownloadBlobParams): UseDownloadBlob => { return { state: "ready", dispatch: async () => { From c79962b933bb3429c5cf409be98893a53f67f3dd Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:09:07 +0300 Subject: [PATCH 05/14] impl state --- src/storage/useDownloadBlob.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 73331b5..f661c30 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -4,6 +4,7 @@ // https://opensource.org/licenses/MIT import { StorageReference } from "firebase/storage"; +import { useState } from "react"; type UseDownloadBlobParams = { reference: StorageReference; @@ -19,8 +20,10 @@ type UseDownloadBlob = { export const useDownloadBlob = ({ reference, }: UseDownloadBlobParams): UseDownloadBlob => { + const [state, setState] = useState("ready"); + return { - state: "ready", + state, dispatch: async () => { throw "tbi"; }, From d1032773b061cb726cf68ee46b61465f068b0753 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:09:53 +0300 Subject: [PATCH 06/14] add loading and done states --- src/storage/useDownloadBlob.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index f661c30..5302615 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -10,7 +10,7 @@ type UseDownloadBlobParams = { reference: StorageReference; }; -type UseDownloadBlobState = "ready"; +type UseDownloadBlobState = "ready" | "loading" | "done"; type UseDownloadBlobDispatcher = () => Promise; type UseDownloadBlob = { state: UseDownloadBlobState; From 3b618b7cc6a32ea8e299d53ccfd3a05b67fb0d98 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:10:22 +0300 Subject: [PATCH 07/14] add blob state --- src/storage/useDownloadBlob.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 5302615..818f4c1 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -21,6 +21,7 @@ export const useDownloadBlob = ({ reference, }: UseDownloadBlobParams): UseDownloadBlob => { const [state, setState] = useState("ready"); + const [blob, setBlob] = useState(undefined); return { state, From 09f948ab75c3ac39832ca61fb799a1b36e7b441e Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:10:53 +0300 Subject: [PATCH 08/14] wip: separate dispatch --- src/storage/useDownloadBlob.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 818f4c1..0d92452 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -23,10 +23,9 @@ export const useDownloadBlob = ({ const [state, setState] = useState("ready"); const [blob, setBlob] = useState(undefined); - return { - state, - dispatch: async () => { - throw "tbi"; - }, + const dispatch: UseDownloadBlobDispatcher = async () => { + throw "tbi"; }; + + return { state, dispatch }; }; From ab7878ebaf9d20fd4c344db1c07a180008d856f7 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:12:56 +0300 Subject: [PATCH 09/14] impl dispatch --- src/storage/useDownloadBlob.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 0d92452..752e42e 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -3,7 +3,7 @@ // This software is released under the MIT License. // https://opensource.org/licenses/MIT -import { StorageReference } from "firebase/storage"; +import { StorageReference, getBlob } from "firebase/storage"; import { useState } from "react"; type UseDownloadBlobParams = { @@ -24,7 +24,11 @@ export const useDownloadBlob = ({ const [blob, setBlob] = useState(undefined); const dispatch: UseDownloadBlobDispatcher = async () => { - throw "tbi"; + setState("loading"); + const blob = await getBlob(reference); + setState("done"); + setBlob(blob); + return blob; }; return { state, dispatch }; From 706ddb6ddb51274ac6e234392373a4308380f219 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:13:32 +0300 Subject: [PATCH 10/14] return blob state --- src/storage/useDownloadBlob.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 752e42e..42791e0 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -13,6 +13,7 @@ type UseDownloadBlobParams = { type UseDownloadBlobState = "ready" | "loading" | "done"; type UseDownloadBlobDispatcher = () => Promise; type UseDownloadBlob = { + blob: Blob | undefined; state: UseDownloadBlobState; dispatch: UseDownloadBlobDispatcher; }; @@ -31,5 +32,5 @@ export const useDownloadBlob = ({ return blob; }; - return { state, dispatch }; + return { blob, state, dispatch }; }; From e3879a9683837af0cfef2e323b6c367d484c7f8f Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:14:04 +0300 Subject: [PATCH 11/14] add adhoc storage reference in tests --- src/storage/useDownloadBlob.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/storage/useDownloadBlob.test.ts b/src/storage/useDownloadBlob.test.ts index 33a85a9..c1addd4 100644 --- a/src/storage/useDownloadBlob.test.ts +++ b/src/storage/useDownloadBlob.test.ts @@ -4,10 +4,14 @@ // https://opensource.org/licenses/MIT import { renderHook } from "@testing-library/react"; +import { ref } from "firebase/storage"; import { useDownloadBlob } from "."; +import { storage } from "../firebase"; + +const reference = ref(storage, "files/README.md"); it("initially, useDownloadBlob hook should have ready state", async () => { - const { result } = renderHook(() => useDownloadBlob()); + const { result } = renderHook(() => useDownloadBlob({ reference })); const { state } = result.current; expect(state).toBe("ready"); }); From ee771b351cf3578dd5e5501011fe853850f081a6 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:15:04 +0300 Subject: [PATCH 12/14] add maxDownloadSizeBytes to dispatch --- src/storage/useDownloadBlob.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/storage/useDownloadBlob.ts b/src/storage/useDownloadBlob.ts index 42791e0..b78be8b 100644 --- a/src/storage/useDownloadBlob.ts +++ b/src/storage/useDownloadBlob.ts @@ -11,7 +11,9 @@ type UseDownloadBlobParams = { }; type UseDownloadBlobState = "ready" | "loading" | "done"; -type UseDownloadBlobDispatcher = () => Promise; +type UseDownloadBlobDispatcher = ( + maxDownloadSizeBytes?: number, +) => Promise; type UseDownloadBlob = { blob: Blob | undefined; state: UseDownloadBlobState; @@ -24,9 +26,9 @@ export const useDownloadBlob = ({ const [state, setState] = useState("ready"); const [blob, setBlob] = useState(undefined); - const dispatch: UseDownloadBlobDispatcher = async () => { + const dispatch: UseDownloadBlobDispatcher = async (maxDownloadSizeBytes) => { setState("loading"); - const blob = await getBlob(reference); + const blob = await getBlob(reference, maxDownloadSizeBytes); setState("done"); setBlob(blob); return blob; From 47bec90323501487f000851e2dea2411a23c35fc Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:17:31 +0300 Subject: [PATCH 13/14] init docs for useDownloadBlob --- docs/hooks/useDownloadBlob.md | 8 ++++++++ docs/storage/downloading-a-file.md | 3 ++- mkdocs.yml | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 docs/hooks/useDownloadBlob.md diff --git a/docs/hooks/useDownloadBlob.md b/docs/hooks/useDownloadBlob.md new file mode 100644 index 0000000..0399dd1 --- /dev/null +++ b/docs/hooks/useDownloadBlob.md @@ -0,0 +1,8 @@ +--- +tags: + - hook +--- + +# `useDownloadBlob` Hook + +Hello. \ No newline at end of file diff --git a/docs/storage/downloading-a-file.md b/docs/storage/downloading-a-file.md index 5136971..98e8bbb 100644 --- a/docs/storage/downloading-a-file.md +++ b/docs/storage/downloading-a-file.md @@ -2,5 +2,6 @@ You can use one of the following ways to download a file from Firebase Storage: - - [`useDownloadLink` hook](../hooks/useDownloadLink.md) + - [`useDownloadLink` hook](../hooks/useDownloadLink.md) to get the link to download + - [`useDownloadBlob` hook](../hooks/useDownloadBlob.md) to directly download the bytes to process it yourself - [`StorageDownloadLink` component](../components/StorageDownloadLink.md) \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 25d62b9..ed11962 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -80,6 +80,7 @@ nav: - hooks/useUploadFile.md - hooks/useUploadFileResumable.md - hooks/useDownloadLink.md + - hooks/useDownloadBlob.md - Components: - Firestore: - components/FirestoreDocument.md From 71ba387c60f47c5811a52244edb28d207aaa5409 Mon Sep 17 00:00:00 2001 From: Eray Erdin Date: Fri, 2 Feb 2024 20:24:26 +0300 Subject: [PATCH 14/14] write docs for useDownloadBlob --- docs/hooks/useDownloadBlob.md | 51 ++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/docs/hooks/useDownloadBlob.md b/docs/hooks/useDownloadBlob.md index 0399dd1..a84a14d 100644 --- a/docs/hooks/useDownloadBlob.md +++ b/docs/hooks/useDownloadBlob.md @@ -5,4 +5,53 @@ tags: # `useDownloadBlob` Hook -Hello. \ No newline at end of file +`useDownloadBlob` hook is used to directly download a file as bytes from Firebase Storage. Instead of [`useDownloadLink` hook](./useDownloadLink.md), this hook might be useful to process a file byte by byte instead of directly downloading to the user's machine. + +A very simple example would be: + +```typescript +const reference = ref(storage, "path/to/remote/file.png"); +const { dispatch } = useDownloadBlob({ reference }); +const blob = await dispatch(file); +``` + +!!! warning + `useDownloadBlob` is lazy by default and will not do anything until you use `dispatch` function. + +You can get the state of the progress with this example. + +```typescript +const { state } = useDownloadBlob({ reference }); +const blob = await dispatch(); +// `state` is "ready" | "loading" | "done" +``` + +`dispatch` method will return an instance of [`Blob`][BlobDoc], but additionally, you can also listen to [`Blob`][BlobDoc] from `useDownloadBlob` hook as well: + +```typescript +const { blob } = useDownloadBlob({ reference }); +// blob updates and rerenders when the state is `"done"` +// until then, it is `undefined` +await dispatch(); +``` + +## Input Parameters + +Input parameters for `useDownloadBlob` hook is as follows: + +| Name | Type | Description | Required | Default Value | +|---|---|---|---|---| +| `reference` | [`firebase/storage/StorageReference`][StorageReferenceRefDoc] | Reference to a file in Storage. | ✅ | - | + +## Return Type + +`useDownloadBlob` hook returns an object with properties as below: + +| Name | Type | Description | +|---|---|---| +| `blob` | [`Blob`][BlobDoc] or `undefined` | The blob of remote file to read. `undefined` if the `state` is not `"done"`. | +| `state` | `"ready" | "loading" | "done"` | The state of the process. | +| `dispatch` | `(maxDownloadSizeBytes? number) => Promise` | A callback to start the process and return the link. You can also define how many bytes to download at most. | + +[StorageReferenceRefDoc]: https://firebase.google.com/docs/reference/js/storage.storagereference +[BlobDoc]: https://developer.mozilla.org/en-US/docs/Web/API/Blob \ No newline at end of file