ไทย

ปลดล็อกพลังของลอจิกที่นำกลับมาใช้ใหม่ได้ในแอปพลิเคชัน React ของคุณด้วย Custom Hooks เรียนรู้วิธีสร้างและใช้ Custom Hooks เพื่อโค้ดที่สะอาดและดูแลรักษาง่ายขึ้น

Custom Hooks: รูปแบบลอจิกที่นำกลับมาใช้ใหม่ได้ใน React

React Hooks ได้ปฏิวัติวิธีการเขียนคอมโพเนนต์ React โดยการนำเสนอ state และฟีเจอร์ lifecycle ให้กับ functional components ในบรรดาประโยชน์มากมายที่พวกเขามอบให้ Custom Hooks โดดเด่นในฐานะกลไกอันทรงพลังสำหรับการดึงและนำลอจิกกลับมาใช้ใหม่ในคอมโพเนนต์ต่างๆ บล็อกโพสต์นี้จะเจาะลึกเข้าไปในโลกของ Custom Hooks สำรวจประโยชน์ การสร้าง และการใช้งานพร้อมตัวอย่างที่นำไปใช้ได้จริง

Custom Hooks คืออะไร?

โดยพื้นฐานแล้ว Custom Hook คือฟังก์ชัน JavaScript ที่ขึ้นต้นด้วยคำว่า "use" และสามารถเรียกใช้ Hooks อื่นๆ ได้ มันช่วยให้คุณสามารถดึงลอจิกของคอมโพเนนต์ออกมาเป็นฟังก์ชันที่นำกลับมาใช้ใหม่ได้ นี่เป็นวิธีที่ทรงพลังในการแบ่งปัน stateful logic, side effects หรือพฤติกรรมที่ซับซ้อนอื่นๆ ระหว่างคอมโพเนนต์โดยไม่ต้องใช้ render props, higher-order components หรือรูปแบบที่ซับซ้อนอื่นๆ

ลักษณะสำคัญของ Custom Hooks:

ประโยชน์ของการใช้ Custom Hooks

Custom Hooks มอบข้อได้เปรียบที่สำคัญหลายประการในการพัฒนา React:

การสร้าง Custom Hook แรกของคุณ

เรามาสาธิตการสร้าง Custom Hook ด้วยตัวอย่างที่ใช้งานได้จริง: hook ที่ติดตามขนาดของหน้าต่าง

ตัวอย่าง: useWindowSize

hook นี้จะคืนค่าความกว้างและความสูงปัจจุบันของหน้าต่างเบราว์เซอร์ และจะอัปเดตค่าเหล่านี้เมื่อหน้าต่างถูกปรับขนาด

import { useState, useEffect } from 'react';

function useWindowSize() {
  const [windowSize, setWindowSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight,
  });

  useEffect(() => {
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    window.addEventListener('resize', handleResize);

    // ลบ event listener ออกเมื่อทำการ cleanup
    return () => window.removeEventListener('resize', handleResize);
  }, []); // อาร์เรย์ว่างเปล่าเพื่อให้แน่ใจว่า effect จะทำงานเฉพาะตอน mount เท่านั้น

  return windowSize;
}

export default useWindowSize;

คำอธิบาย:

  1. นำเข้า Hooks ที่จำเป็น: เรานำเข้า useState และ useEffect จาก React
  2. กำหนด Hook: เราสร้างฟังก์ชันชื่อ useWindowSize โดยยึดตามธรรมเนียมการตั้งชื่อ
  3. เริ่มต้น State: เราใช้ useState เพื่อเริ่มต้น state windowSize ด้วยความกว้างและความสูงเริ่มต้นของหน้าต่าง
  4. ตั้งค่า Event Listener: เราใช้ useEffect เพื่อเพิ่ม resize event listener ไปยังหน้าต่าง เมื่อหน้าต่างถูกปรับขนาด ฟังก์ชัน handleResize จะอัปเดต state windowSize
  5. Cleanup: เราคืนค่าฟังก์ชัน cleanup จาก useEffect เพื่อลบ event listener เมื่อคอมโพเนนต์ unmount ซึ่งจะช่วยป้องกันหน่วยความจำรั่วไหล (memory leaks)
  6. คืนค่า: hook จะคืนค่าอ็อบเจกต์ windowSize ซึ่งประกอบด้วยความกว้างและความสูงปัจจุบันของหน้าต่าง

การใช้ Custom Hook ในคอมโพเนนต์

เมื่อเราสร้าง Custom Hook ของเราแล้ว มาดูกันว่าจะใช้งานในคอมโพเนนต์ React ได้อย่างไร

import React from 'react';
import useWindowSize from './useWindowSize';

function MyComponent() {
  const { width, height } = useWindowSize();

  return (
    

ความกว้างหน้าต่าง: {width}px

ความสูงหน้าต่าง: {height}px

); } export default MyComponent;

คำอธิบาย:

  1. นำเข้า Hook: เรานำเข้า Custom Hook useWindowSize
  2. เรียกใช้ Hook: เราเรียกใช้ hook useWindowSize ภายในคอมโพเนนต์
  3. เข้าถึงค่า: เราใช้ destructuring กับอ็อบเจกต์ที่ส่งคืนมาเพื่อรับค่า width และ height
  4. แสดงผลค่า: เราแสดงผลค่าความกว้างและความสูงใน UI ของคอมโพเนนต์

คอมโพเนนต์ใดๆ ที่ใช้ useWindowSize จะอัปเดตโดยอัตโนมัติเมื่อขนาดของหน้าต่างเปลี่ยนแปลง

ตัวอย่างที่ซับซ้อนยิ่งขึ้น

เรามาสำรวจกรณีการใช้งานขั้นสูงสำหรับ Custom Hooks กัน

ตัวอย่าง: useLocalStorage

hook นี้ช่วยให้คุณสามารถจัดเก็บและดึงข้อมูลจาก local storage ได้อย่างง่ายดาย

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // State สำหรับเก็บค่าของเรา
  // ส่งค่าเริ่มต้นไปยัง useState เพื่อให้ลอจิกทำงานเพียงครั้งเดียว
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // ดึงข้อมูลจาก local storage ด้วย key
      const item = window.localStorage.getItem(key);
      // แปลง JSON ที่เก็บไว้ หรือถ้าไม่มีให้คืนค่า initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // หากเกิดข้อผิดพลาดก็ให้คืนค่า initialValue เช่นกัน
      console.log(error);
      return initialValue;
    }
  });

  // คืนค่าฟังก์ชัน setter ของ useState ในเวอร์ชันที่ห่อหุ้มไว้ ซึ่ง...
  // ...จะบันทึกค่าใหม่ลงใน localStorage
  const setValue = (value) => {
    try {
      // อนุญาตให้ value เป็นฟังก์ชันเพื่อให้เรามี API เหมือนกับ useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // บันทึกลงใน local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // บันทึก state
      setStoredValue(valueToStore);
    } catch (error) {
      // การใช้งานขั้นสูงกว่านี้จะมีการจัดการกรณีเกิดข้อผิดพลาด
      console.log(error);
    }
  };

  useEffect(() => {
    try {
      const item = window.localStorage.getItem(key);
      setStoredValue(item ? JSON.parse(item) : initialValue);
    } catch (error) {
      console.log(error);
    }
  }, [key, initialValue]);

  return [storedValue, setValue];
}

export default useLocalStorage;

การใช้งาน:

import React from 'react';
import useLocalStorage from './useLocalStorage';

function MyComponent() {
  const [name, setName] = useLocalStorage('name', 'Guest');

  return (
    

สวัสดี, {name}!

setName(e.target.value)} />
); } export default MyComponent;

ตัวอย่าง: useFetch

hook นี้จะห่อหุ้มลอจิกสำหรับการดึงข้อมูลจาก API

import { useState, useEffect } from 'react';

function useFetch(url) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    async function fetchData() {
      try {
        const response = await fetch(url);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const json = await response.json();
        setData(json);
        setLoading(false);
      } catch (error) {
        setError(error);
        setLoading(false);
      }
    }

    fetchData();
  }, [url]);

  return { data, loading, error };
}

export default useFetch;

การใช้งาน:

import React from 'react';
import useFetch from './useFetch';

function MyComponent() {
  const { data, loading, error } = useFetch('https://jsonplaceholder.typicode.com/todos/1');

  if (loading) return 

กำลังโหลด...

; if (error) return

ข้อผิดพลาด: {error.message}

; return (

หัวข้อ: {data.title}

เสร็จสิ้น: {data.completed ? 'ใช่' : 'ไม่'}

); } export default MyComponent;

แนวทางปฏิบัติที่ดีที่สุดสำหรับ Custom Hooks

เพื่อให้แน่ใจว่า Custom Hooks ของคุณมีประสิทธิภาพและสามารถบำรุงรักษาได้ ควรปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุดเหล่านี้:

ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง

รูปแบบขั้นสูง

การประกอบ Custom Hooks เข้าด้วยกัน

Custom Hooks สามารถนำมาประกอบเข้าด้วยกันเพื่อสร้างลอจิกที่ซับซ้อนมากขึ้น ตัวอย่างเช่น คุณสามารถรวม useLocalStorage hook กับ useFetch hook เพื่อบันทึกข้อมูลที่ดึงมาลงใน local storage โดยอัตโนมัติ

การแบ่งปันลอจิกระหว่าง Hooks

หาก Custom Hooks หลายตัวมีลอจิกร่วมกัน คุณสามารถดึงลอจิกนั้นออกมาเป็นฟังก์ชัน utility ที่แยกต่างหากและนำกลับมาใช้ในทั้งสอง hooks ได้

การใช้ Context กับ Custom Hooks

Custom Hooks สามารถใช้ร่วมกับ React Context เพื่อเข้าถึงและอัปเดต global state ได้ ซึ่งช่วยให้คุณสร้างคอมโพเนนต์ที่นำกลับมาใช้ใหม่ได้ซึ่งรับรู้และสามารถโต้ตอบกับ global state ของแอปพลิเคชันได้

ตัวอย่างในโลกแห่งความเป็นจริง

นี่คือตัวอย่างบางส่วนของวิธีที่ Custom Hooks สามารถนำไปใช้ในแอปพลิเคชันในโลกแห่งความเป็นจริงได้:

ตัวอย่าง : useGeolocation hook สำหรับแอปพลิเคชันข้ามวัฒนธรรม เช่น แอปแผนที่หรือบริการจัดส่ง

import { useState, useEffect } from 'react';

function useGeolocation() {
  const [location, setLocation] = useState({
    latitude: null,
    longitude: null,
    error: null,
  });

  useEffect(() => {
    if (!navigator.geolocation) {
      setLocation({
        latitude: null,
        longitude: null,
        error: 'เบราว์เซอร์นี้ไม่รองรับ Geolocation',
      });
      return;
    }

    const watchId = navigator.geolocation.watchPosition(
      (position) => {
        setLocation({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude,
          error: null,
        });
      },
      (error) => {
        setLocation({
          latitude: null,
          longitude: null,
          error: error.message,
        });
      }
    );

    return () => navigator.geolocation.clearWatch(watchId);
  }, []);

  return location;
}

export default useGeolocation;

สรุป

Custom Hooks เป็นเครื่องมืออันทรงพลังสำหรับการเขียนโค้ด React ที่สะอาดขึ้น, นำกลับมาใช้ใหม่ได้มากขึ้น และบำรุงรักษาง่ายขึ้น ด้วยการห่อหุ้มลอจิกที่ซับซ้อนไว้ใน Custom Hooks คุณสามารถทำให้คอมโพเนนต์ของคุณเรียบง่ายขึ้น ลดการทำซ้ำของโค้ด และปรับปรุงโครงสร้างโดยรวมของแอปพลิเคชันของคุณได้ จงใช้ Custom Hooks และปลดล็อกศักยภาพในการสร้างแอปพลิเคชัน React ที่แข็งแกร่งและขยายขนาดได้

เริ่มต้นด้วยการระบุส่วนต่างๆ ใน codebase ที่มีอยู่ของคุณซึ่งมีการใช้ลอจิกซ้ำๆ ในหลายคอมโพเนนต์ จากนั้นทำการ refactor ลอจิกนั้นให้เป็น Custom Hooks เมื่อเวลาผ่านไป คุณจะสร้างคลังของ hooks ที่นำกลับมาใช้ใหม่ได้ซึ่งจะช่วยเร่งกระบวนการพัฒนาและปรับปรุงคุณภาพโค้ดของคุณ

อย่าลืมปฏิบัติตามแนวทางปฏิบัติที่ดีที่สุด หลีกเลี่ยงข้อผิดพลาดทั่วไป และสำรวจรูปแบบขั้นสูงเพื่อใช้ประโยชน์สูงสุดจาก Custom Hooks ด้วยการฝึกฝนและประสบการณ์ คุณจะกลายเป็นผู้เชี่ยวชาญด้าน Custom Hooks และเป็นนักพัฒนา React ที่มีประสิทธิภาพยิ่งขึ้น