Hi, It's me again.
In this post, I share to you how can I manage or CRUD the file in google firebase - storage with React.
Create react app with nextjs framework
create-next-app nextjs-crud-gg --ts
Installing the libraries
npm i -s firebase uuid && npm i --dev @types/uuid
Creating the structure of project.
- storage.ts in libs folder - (root_project)/libs/storage.ts
- fileManage.ts in utils folder - (root_project)/utils/fileManage.ts
- Add env variable to next.config.js
- Custom the index.tsx page - We just use one page to CRUD the file as the demo page.
I. Setup google firebase storage in storage.ts
import { initializeApp } from 'firebase/app';
import { getStorage } from 'firebase/storage';
const firebaseConfig = {
apiKey: process.env.GOOGLE_API_KEY,
authDomain: process.env.GOOGLE_AUTH_DOMAIN,
projectId: process.env.GOOGLE_PROJECT_ID,
storageBucket: process.env.GOOGLE_STORAGE_BUCKET,
messagingSenderId: process.env.MESSAGING_SENDER_ID,
appId: process.env.GOOGLE_APP_ID,
measurementId: process.env.GOOGLE_MEASUREMENT_ID,
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const storage = getStorage(app);
export { storage };
II. Setup environment variables in the next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
env: {
GOOGLE_API_KEY: <value_here>,
GOOGLE_AUTH_DOMAIN: <value_here>,
GOOGLE_PROJECT_ID: <value_here>,
GOOGLE_STORAGE_BUCKET: <value_here>,
MESSAGING_SENDER_ID: <value_here>,
GOOGLE_APP_ID: <value_here>,
GOOGLE_MEASUREMENT_ID: <value_here>,
},
};
module.exports = nextConfig;
To figure out, how we can get
<value_here>
. Please refer to this link firebase.google.com
III. Make a library to manage the file in fileManage.ts
import { storage } from '../libs/storage';
import {
deleteObject,
getDownloadURL,
listAll,
ref,
uploadBytes,
UploadResult,
} from 'firebase/storage';
import { v4 } from 'uuid';
/**
* Get all file by folder name.
*
* @param string folder image.
* @returns array File of url.
*/
export async function getAllFile(folder: string) {
const filesRef = ref(storage, `${folder}`);
const files = (await listAll(filesRef)).items;
return Promise.all(
files.map(async (fileRef) => {
return await getDownloadURL(fileRef);
}),
);
}
/**
* Get file by url.
*
* @param string url image.
* @returns boolean true if deleted file.
*/
export async function getFile(url: string) {
const fileRef = ref(storage, url);
return await getDownloadURL(fileRef);
}
/**
* Delete file by url.
*
* @param string url image.
* @returns boolean true if deleted file.
*/
export async function deleteFile(url: string) {
const fileRef = ref(storage, url);
await deleteObject(fileRef);
}
/**
* Upload file to google firebase storage.
*
* @param string folder name.
* @param array filesUpload list of file
* @returns array list of url file.
*/
export async function uploadFile(folder: string, filesUpload: File[]) {
return Promise.all(
[...filesUpload].map(async (file: File) => {
const fileRef = ref(storage, `${folder}/${file.name + v4()}`);
const value: UploadResult = await uploadBytes(fileRef, file);
return await getDownloadURL(value.ref);
}),
);
}
Method | Description |
---|---|
getAllFile | Get all the file in google firebase storage base the the fodler name |
getFile | Get single file based on the url of file |
deleteFile | Delete file based on the url of file |
uploadFile | Upload multiple file |
updateFile | Well, we can delete the file which uploaded before we upload the new file. That make easy and simple. We can use the methods: "deleteFile" + "uploadFile". |
VI. Manage the file with React
I will edit the index.tsx page
import type { NextPage } from 'next';
import { useRef, useState } from 'react';
import { deleteFile, getAllFile, uploadFile } from '../utils/fileManager';
const Home: NextPage = () => {
// Hook for upload the file
const [images, setImages] = useState<File[]>([]);
// Hook for preview the file uploaded.
const [imagesUploaded, setImageUploaded] = useState<string[]>([]);
// Hook for list all the file in the "images" folder.
const [imageGallery, setImageGallery] = useState<string[]>([]);
// Use fileRef to clean the file after uploaded.
const fileRef = useRef<HTMLInputElement>(null);
// Creating the folder in google firebase storage. I named the "images" for contain only the type of image.
const FOLDER_NAME = 'images';
/**
* Add file uploaded
* @param e Event HTML Input Change
*/
const handleOnChange = (e: any) => {
setImages(e.target.files as File[]);
e.target.files = null;
};
/**
* Delete the file with url file.
* @param url string
*/
const handleOnDelete = (url: string) => {
deleteFile(url).then(() => {
setImageUploaded((prev) => prev.filter((img) => img !== url));
setImageGallery((prev) => prev.filter((img) => img !== url));
alert(`Deleted file`);
});
};
/**
* Upload file, and show alert if success.
*/
const handleOnUpload = () => {
if (images.length === 0) return false;
uploadFile(FOLDER_NAME, images).then((imageList) => {
setImageUploaded(imageList);
alert('Upload file successed');
if (fileRef.current) {
fileRef.current.value = '';
}
});
};
/**
* Get all the files base on the folder name.
*/
const handleGetFiles = () => {
getAllFile(FOLDER_NAME)
.then((listImages) => {
setImageGallery(listImages);
})
.catch((err) => {
console.log('Something went wrong', err);
});
};
return (
<div className="app">
<div className="form-control">
<label htmlFor="file">
<input
type="file"
ref={fileRef}
onChange={handleOnChange}
multiple
/>
</label>
<button
className="button"
onClick={handleOnUpload}
>
Upload file to firebase storage
</button>
</div>
<div className="image-container">
<p>Image preview</p>
<ul className="image-container__list">
{imagesUploaded.length > 0 &&
imagesUploaded.map((image) => (
<li
style={{ listStyle: 'none' }}
key={image}
>
<img
src={image}
width="100%"
/>
<button
type="button"
onClick={() => handleOnDelete(image)}
>
Delete file
</button>
</li>
))}
</ul>
</div>
<div className="image-container-gallery">
<h1>
Image Gallery
<button
className="button"
onClick={handleGetFiles}
>
Click me to get it !!!
</button>
</h1>
<div className="image-container">
<ul className="image-container__list">
{imageGallery.length > 0 &&
imageGallery.map((image) => (
<li
style={{ listStyle: 'none' }}
key={image}
>
<img
src={image}
width="100%"
/>
<button
type="button"
onClick={() => handleOnDelete(image)}
>
Delete file
</button>
</li>
))}
</ul>
</div>
</div>
</div>
);
};
export default Home;
V. That it's. Hope you doing great.
Thank for reading
Have a good day.
Thang Em No Dev.
Top comments (0)