Tiếng Việt

Khai phá sức mạnh của logic tái sử dụng trong ứng dụng React của bạn với custom hooks. Học cách tạo và tận dụng custom hooks để có mã nguồn sạch hơn và dễ bảo trì hơn.

Custom Hooks: Các Mẫu Logic Tái Sử Dụng trong React

React Hooks đã cách mạng hóa cách chúng ta viết các thành phần React bằng cách giới thiệu các tính năng về trạng thái và vòng đời cho các thành phần chức năng. Trong số nhiều lợi ích mà chúng mang lại, custom hooks nổi bật như một cơ chế mạnh mẽ để trích xuất và tái sử dụng logic trên nhiều thành phần. Bài đăng blog này sẽ đi sâu vào thế giới của custom hooks, khám phá lợi ích, cách tạo và sử dụng chúng với các ví dụ thực tế.

Custom Hooks là gì?

Về cơ bản, một custom hook là một hàm JavaScript bắt đầu bằng từ "use" và có thể gọi các hook khác. Chúng cho phép bạn trích xuất logic của thành phần vào các hàm có thể tái sử dụng. Đây là một cách mạnh mẽ để chia sẻ logic có trạng thái, các hiệu ứng phụ hoặc các hành vi phức tạp khác giữa các thành phần mà không cần dùng đến render props, higher-order components hoặc các mẫu phức tạp khác.

Các đặc điểm chính của Custom Hooks:

Lợi ích của việc sử dụng Custom Hooks

Custom hooks mang lại một số lợi thế đáng kể trong việc phát triển React:

Tạo Custom Hook đầu tiên của bạn

Hãy minh họa việc tạo một custom hook bằng một ví dụ thực tế: một hook theo dõi kích thước cửa sổ.

Ví dụ: useWindowSize

Hook này sẽ trả về chiều rộng và chiều cao hiện tại của cửa sổ trình duyệt. Nó cũng sẽ cập nhật các giá trị này khi cửa sổ được thay đổi kích thước.

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);

    // Remove event listener on cleanup
    return () => window.removeEventListener('resize', handleResize);
  }, []); // Empty array ensures that effect is only run on mount

  return windowSize;
}

export default useWindowSize;

Giải thích:

  1. Nhập các Hook cần thiết: Chúng ta nhập useStateuseEffect từ React.
  2. Định nghĩa Hook: Chúng ta tạo một hàm có tên useWindowSize, tuân thủ quy ước đặt tên.
  3. Khởi tạo trạng thái: Chúng ta sử dụng useState để khởi tạo trạng thái windowSize với chiều rộng và chiều cao ban đầu của cửa sổ.
  4. Thiết lập trình lắng nghe sự kiện: Chúng ta sử dụng useEffect để thêm một trình lắng nghe sự kiện resize vào cửa sổ. Khi cửa sổ được thay đổi kích thước, hàm handleResize sẽ cập nhật trạng thái windowSize.
  5. Dọn dẹp: Chúng ta trả về một hàm dọn dẹp từ useEffect để xóa trình lắng nghe sự kiện khi thành phần bị gỡ bỏ. Điều này ngăn chặn rò rỉ bộ nhớ.
  6. Trả về giá trị: Hook trả về đối tượng windowSize, chứa chiều rộng và chiều cao hiện tại của cửa sổ.

Sử dụng Custom Hook trong một Component

Bây giờ chúng ta đã tạo xong custom hook, hãy xem cách sử dụng nó trong một thành phần React.

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

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

  return (
    

Window width: {width}px

Window height: {height}px

); } export default MyComponent;

Giải thích:

  1. Nhập Hook: Chúng ta nhập custom hook useWindowSize.
  2. Gọi Hook: Chúng ta gọi hook useWindowSize bên trong thành phần.
  3. Truy cập các giá trị: Chúng ta sử dụng destructuring để lấy các giá trị widthheight từ đối tượng được trả về.
  4. Kết xuất các giá trị: Chúng ta kết xuất các giá trị chiều rộng và chiều cao trong giao diện người dùng của thành phần.

Bất kỳ thành phần nào sử dụng useWindowSize sẽ tự động cập nhật khi kích thước cửa sổ thay đổi.

Các ví dụ phức tạp hơn

Hãy khám phá một số trường hợp sử dụng nâng cao hơn cho các custom hooks.

Ví dụ: useLocalStorage

Hook này cho phép bạn dễ dàng lưu trữ và truy xuất dữ liệu từ local storage.

import { useState, useEffect } from 'react';

function useLocalStorage(key, initialValue) {
  // State to store our value
  // Pass initial value to useState so logic is only executed once
  const [storedValue, setStoredValue] = useState(() => {
    try {
      // Get from local storage by key
      const item = window.localStorage.getItem(key);
      // Parse stored json or if none return initialValue
      return item ? JSON.parse(item) : initialValue;
    } catch (error) {
      // If error also return initialValue
      console.log(error);
      return initialValue;
    }
  });

  // Return a wrapped version of useState's setter function that ...
  // ... persists the new value to localStorage.
  const setValue = (value) => {
    try {
      // Allow value to be a function so we have same API as useState
      const valueToStore = value instanceof Function ? value(storedValue) : value;
      // Save to local storage
      window.localStorage.setItem(key, JSON.stringify(valueToStore));
      // Save state
      setStoredValue(valueToStore);
    } catch (error) {
      // A more advanced implementation would handle the error case
      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;

Cách sử dụng:

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

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

  return (
    

Hello, {name}!

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

Ví dụ: useFetch

Hook này đóng gói logic để tìm nạp dữ liệu từ một 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;

Cách sử dụng:

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

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

  if (loading) return 

Loading...

; if (error) return

Error: {error.message}

; return (

Title: {data.title}

Completed: {data.completed ? 'Yes' : 'No'}

); } export default MyComponent;

Các phương pháp hay nhất cho Custom Hooks

Để đảm bảo rằng các custom hooks của bạn hiệu quả và có thể bảo trì, hãy tuân theo các phương pháp hay nhất sau:

Những cạm bẫy phổ biến cần tránh

Các mẫu nâng cao

Kết hợp các Custom Hooks

Các custom hooks có thể được kết hợp với nhau để tạo ra logic phức tạp hơn. Ví dụ, bạn có thể kết hợp một hook useLocalStorage với một hook useFetch để tự động lưu dữ liệu đã tìm nạp vào local storage.

Chia sẻ Logic giữa các Hook

Nếu nhiều custom hooks chia sẻ logic chung, bạn có thể trích xuất logic đó vào một hàm tiện ích riêng và tái sử dụng nó trong cả hai hook.

Sử dụng Context với Custom Hooks

Custom hooks có thể được sử dụng cùng với React Context để truy cập và cập nhật trạng thái toàn cục. Điều này cho phép bạn tạo các thành phần có thể tái sử dụng nhận biết và có thể tương tác với trạng thái toàn cục của ứng dụng.

Các ví dụ trong thực tế

Dưới đây là một số ví dụ về cách các custom hooks có thể được sử dụng trong các ứng dụng thực tế:

Ví dụ : hook useGeolocation cho các ứng dụng đa văn hóa như bản đồ hoặc dịch vụ giao hàng

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 is not supported by this browser.',
      });
      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;

Kết luận

Custom hooks là một công cụ mạnh mẽ để viết mã React sạch hơn, có thể tái sử dụng hơn và dễ bảo trì hơn. Bằng cách đóng gói logic phức tạp trong các custom hooks, bạn có thể đơn giản hóa các thành phần của mình, giảm sự trùng lặp mã và cải thiện cấu trúc tổng thể của các ứng dụng của bạn. Hãy nắm bắt custom hooks và khai phá tiềm năng của chúng để xây dựng các ứng dụng React mạnh mẽ và có khả năng mở rộng hơn.

Bắt đầu bằng cách xác định các khu vực trong codebase hiện tại của bạn nơi logic đang được lặp lại trên nhiều thành phần. Sau đó, tái cấu trúc logic đó thành các custom hooks. Theo thời gian, bạn sẽ xây dựng một thư viện các hook có thể tái sử dụng, giúp tăng tốc quá trình phát triển và cải thiện chất lượng mã của bạn.

Hãy nhớ tuân theo các phương pháp hay nhất, tránh các cạm bẫy phổ biến và khám phá các mẫu nâng cao để tận dụng tối đa custom hooks. Với thực hành và kinh nghiệm, bạn sẽ trở thành một bậc thầy về custom hooks và một nhà phát triển React hiệu quả hơn.