Ionic Framework

วิธีใช้ Firebase Hooks ใน Ionic React

เรื่องที่เกี่ยวข้อง - , ,

หลังจากที่ 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 เราจะทำการดึงเอา

  1. error ที่อาจเกิดขึ้นระหว่าง upload file
  2. สถานะของการอัพโหลดไฟล์
<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 ของเราเอง

ติดตามเรื่องใหม่ๆ ได้ตามช่องทางต่อไปนี้ครับ

อ้างอิง – Ionic Blog, Github Repo 1 (Full version), Repo 2 (File upload hook only)

Loading Facebook Comments ...

Leave a Reply

Your email address will not be published. Required fields are marked *

Fill out this field
Fill out this field
Please enter a valid email address.

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Menu