หลังจากที่ Ionic รองรับการเขียน React ก็มีตัวอย่างโปรเจคสาธิตออกมามากมาย พลไปเจอตัวอย่างหนึ่งของการทำ Firebase Hooks กับตัว Ionic React มาสรุปเป็นภาษาไทยให้ได้ลองกันครับ
รู้จักกับ React Hooks ก่อน
React hooks เป็นกลไกล่าสุดในจักรวาล React ที่ทำให้เราสามารถใช้งาน State และกลไกอื่นๆ ของ React ได้โดยไม่ต้องเขียนในรูปแบบของ Class Component
ตอนเราเขียน Component จะเห็นว่า เรามีการเขียนแบบ Function และแบบ Class
เขียน React Component แบบ function
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
เขียน React Component แบบ Class
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}</h1>;
}
}
ซึ่งก่อนการมาถึงของ React Hooks แบบ Class จะได้รับความนิยมมากกว่า เพราะสามารถจัดการ State และกลไกอื่นๆ ได้ในรูปแบบที่ค่อนข้างง่ายกว่าแบบ Function
และ React Hooks เกิดมาเพื่อคืนความเรียบง่ายของ React Component สู่รูปแบบของ Function นั่นเอง ดังนั้นไม่มีการบังคับว่าเราชอบเขียนแบบ Function หรือแบบ Class อีกต่อไปครับ
แต่สไตล์ของ React Hooks ก็จะแหวกแนวจากแบบ Class ไปเลยนะ
แล้ว hooks ที่สร้างขึ้นใช้เอง ก็จะเรียกว่า Custom Hooks ครับ Firebase hook ก็เป็นหนึ่งใน custom hooks ของเราวันนี้
เริ่มต้นใช้ Firebase Hooks
อย่างแรกคือ เราต้อง Import และ setup ตัว custom hooks และ Setup ให้เรียบร้อย
// custom hook that will upload to firebase
import useFirebaseUpload from "../hooks/useFirebaseUpload";
// setting up the hook to upload file and track its progress
const [ { data, isLoading, isError, progress }, setFileData ] = useFirebaseUpload();
จากนั้นใน parent component เราจะทำการดึงเอา
- error ที่อาจเกิดขึ้นระหว่าง upload file
- สถานะของการอัพโหลดไฟล์
<IonContent>
{/* get error from hook and display if necessary */}
{isError && <div>ERROR: {isError.message}</div>}
{/* get loading info from hook & display progress if necessary */}
{isLoading && progress && (
<IonProgressBar value={progress.value}></IonProgressBar>
) }
</IonContent>
ส่วนสุดท้ายของ Component จะเป็นตัวแบบฟอร์มสำหรับกดอัพโหลดไฟล์ จะใช้ hook function ที่ชื่อ setFileData()
ที่เรา setup ไว้ตอนแรกนั่นเอง
{/* user selects a file and returns the info required for upload */}
<input
type="file"
onChange={(e: any) => setFileData(e.target.files[0])}
/>
กลไกของ Firebase File Upload Hook
วิธีใช้งาน File Upload ของ Firebase Hook เราจะตั้งค่าที่จำเป็นต่างๆ ของ Firebase ให้เรียบร้อย
วิธีการตั้งค่าส่วนนี้ สามารถดูได้จากคำแนะนำวิธีใช้งาน Firebase ครับ
import { useState, useEffect } from "react";
import firebase from "firebase";
var firebaseConfig = {
// ADD YOUR FIREBASE CONFIGURATION
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
// the firebase reference to storage
const storageRef = firebase.storage().ref();
และในที่นี้เราใช้งาน typescript เราต้องมีการกำหนด interface สำหรับใช้ใน hook เพื่อกำหนดเป็น type ของค่าที่ return ออกมาจาก hook ครับ
interface UploadDataResponse { metaData: firebase.storage.FullMetadata, downloadUrl: any };
interface ProgressResponse { value: number }
function FirebaseFileUploadApi(): [{
data: UploadDataResponse | undefined,
isLoading: boolean,
isError: any,
progress: ProgressResponse | null
},
Function
] { //additional code... }
จากนั้นเราจึงไล่กำหนดค่า state ที่ต้องใช้ใน hook
// the data from the firebase file upload response
const [data, setData] = useState<UploadDataResponse | undefined>();
// sets properties on the file to be uploaded, this is called
// by the parent component
const [fileData, setFileData] = useState<File | null>();
// if we are loading a file or not
const [isLoading, setIsLoading] = useState<boolean>(false);
// if an error happened during the process
const [isError, setIsError] = useState<any>(false);
// used for tracking the % of upload completed
const [progress, setProgress] = useState<ProgressResponse | null>(null);
การประยุกต์ใช้ useEffect
useEffect
จะทำงานทุกครั้งหลังจาก Component ถูก render เราจึงสามารถควบคุมลำดับการ render นี้ได้ด้วยการกำหนด array เป็น parameter ตัวที่ 2
ในที่นี้ custom hook ของเรา ต้องการให้ทำงานเฉพาะตอนที่ค่า fileData
เปลี่ยน นั่นหมายถึงผู้ใช้ต้องเลือกไฟล์ในการอัพโหลด และเราสามารถตรวจจับการทำงานนี้ได้โดยการเรียกใช้ Method ชื่อ setData
// this function will be called when the any properties in the dependency array changes
useEffect(() => {
const uploadData = async () => {
// initialize upload information
setIsError(false);
setIsLoading(true);
setProgress({ value: 0 });
if (!fileData) return;
// wrap in a try catch block to update the error state
try {
let fName = `${(new Date()).getTime()}-${fileData.name}`
// setting the firebase properties for the file upload
let ref = storageRef.child("images/" + fName);
let uploadTask = ref.put(fileData);
// tracking the state of the upload to assist in updating the
// application UI
//
// method details covered in the next section...
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
_progress => { },
_error => { },
async () => { }
);
} catch (_error) {
setIsLoading(false);
setIsError(_error);
}
};
fileData && uploadData();
}, [fileData]);
การจัดการสถานะของ State ของ File Upload ใน Firebase
ตอนที่เราเรียกใช้ ref.put(fileData)
จะมีการคืนค่าที่เราสามารถใช้เช็คสถานะของการอัพโหลดไฟล์ได้
ตัวแปรที่คืนกลับมาให้เรานี้ สามารถเช็คได้ทั้ง error, สถานะการอัพโหลด, หรือการอัพโหลดที่เสร็จสมบูรณ์
ใน custom hooks ของเรานี้ มีการใส่ handler สำหรับเหตุการณ์ดังกล่าวแต่และแบบเอาไว้ และทำให้สามารถเข้าถึงได้จากตัว hook เอง
เช่นในที่นี้เรามีการเรียกใช้ Firebase ที่ชื่อ uploadTask.snapshot.ref.getDownloadURL()
ที่จะทำให้เราได้ URL มาแสดงผลเป็นภาพในแอพพลิเคชั่นของเรา
// tracking the state of the upload to assist in updating the
// application UI
uploadTask.on(
firebase.storage.TaskEvent.STATE_CHANGED,
_progress => {
var value =
(_progress.bytesTransferred / _progress.totalBytes);
console.log("Upload is " + value * 100 + "% done");
setProgress({ value });
},
_error => {
setIsLoading(false);
setIsError(_error);
},
// completion handler
async () => {
setIsError(false);
setIsLoading(false);
// need to get the url to download the file
let downloadUrl = await uploadTask.snapshot.ref.getDownloadURL();
// set the data when upload has completed
setData({
metaData: uploadTask.snapshot.metadata,
downloadUrl
});
// reset progress
setProgress(null);
}
);
สรุป
น่าจะเห็นวิธีการอีกแบบในการใช้ Custom Hooks ใน React อีกแบบนะครับ ตัวอย่างนี้ค่อนข้างให้ภาพชัดเจนในการเรียกใช้บริการของ Firebase ในส่วนของ File Upload มาใช้ใน Custom Hook ของเราเอง
ติดตามเรื่องใหม่ๆ ได้ตามช่องทางต่อไปนี้ครับ
- ติดตามจากแฟนเพจ Nextflow
- กดติดตามคลิปใหม่ๆ Subscribe YouTube Channel ของพลได้เลย
- โทรติดต่อบริการจัดอบรม 083-071-3373 คลิกโทรผ่านมือถือได้เลย
- สอบถามผ่านทาง LINE คลิก
- สอบถามผ่านทาง Facebook คลิก
อ้างอิง – Ionic Blog, Github Repo 1 (Full version), Repo 2 (File upload hook only)