Một số custom hooks hay sử dụng cho React

830

Hooks là một bổ sung mới trong React 16.8, nó là những function cho phép bạn kết nối React state và lifecycle vào các components sử dụng hàm. React cung cấp cho chúng ta những hooks có sẵn như useState, useEffect, useMemo, … và đang tiếp tục bổ sung thêm các hooks hữu ích khác trong các phiên bản React mới. Không chỉ có vậy, React cũng có phép chúng ta tự định nghĩa các custom hooks để sử dụng. Trong bài viết này mình sẽ giới thiệu một vài custom hooks hữu ích cho các bạn tham khảo nhé.

useWindowSize

Trường hợp chúng ta muốn lấy kích thước của trình duyệt (chiều rộng và chiều cao), ta có thể sử dụng hook dưới đây; lưu ý là trường hợp code chạy phía server (server-side) thì biến window sẽ trả về undefined.

function useWindowSize() {
  // biến kiểm tra nó có phải client hay không
  const isClient = typeof window === "object";

  // lấy chiều rộng và chiều cao của cửa sổ của trình duyệt đang có
  function getSize() {
    return {
      width: isClient ? window.innerWidth : undefined,
      height: isClient ? window.innerHeight : undefined,
    };
  }

  // state quản lý kích thước của trình duyệt
  const [windowSize, setWindowSize] = useState(getSize);

  // effect set kích thước của cửa sổ của trình duyệt
  useEffect(() => {
    if (!isClient) {
      return false;
    }

    // set state kích thước của trình duyệt
    function handleResize() {
      setWindowSize(getSize());
    }

    // lắng nghe sự thay đổi kích thước của trình duyệt và set lại
    window.addEventListener("resize", handleResize);
    return () => window.removeEventListener("resize", handleResize);
  }, []); // chỉ chạy khi mount và unmount
  return windowSize;
}

useQueryString hay usePushQueryString

React Router không hỗ trợ query string, nên nếu bạn muốn xử lý URL có chứa params thì việc tạo 2 custom hook dưới đây là việc cần thiết. Trong 2 hooks này mình sử dụng thêm thư viện query-string cho việc get hay set giá trị URL.

import { useMemo } from "react";
import { useLocation } from "react-router-dom";
import qs from "query-string";

function useQueryString() {
  const location = useLocation();
  const queryString = useMemo(
    () => qs.parse(location.search),
    [location.search]
  );

  return queryString; // { page: 1, search: 'deptrai', filter: 'male' }
}

export default useQueryString;
import { useHistory, useLocation } from 'react-router-dom';
import qs from 'query-string';

function usePushQueryString() {
  const location = useLocation();
  const history = useHistory();

  function handlePushLocationSearch(data) {
    const locationSearch = qs.parse(location.search);

    history.push({ search: `?${qs.stringify({ ...locationSearch, ...data })}` });
 }

  return handlePushLocationSearch;
}

export default usePushQueryString;

useScrollToTop

Hook đơn giản nhất mình viết nhưng cũng được sử dụng rất nhiều, đấy là tính năng cuộn lên đầu trang web. Cũng lưu ý các bạn là chỉ sử dụng khi ứng dụng render ở client thôi nhé.

import React, { useLayoutEffect } from 'react'

function useScrollToTop() {
    useLayoutEffect(() => {
       window.scrollTo( 0,0)
    }, [])
}

export default useScrollToTop

useCookie

Một hook mình viết khi sử dụng thư viện js-cookie cho việc quản lý cookie trang web React của mình. Cookie giúp các bạn lưu trữ thông tin phiên đăng nhập và xác thực website.

import { useState } from "react";
import * as Cookies from "js-cookie";

/**
 * useCookie - React Hook for Cookies based on js-cookie
 * @param {string} key Cookie 
 * @param {Object|string} [initialValue]  Value will be assign if cookie doesn't exist.
 * @returns {Array} Returns cookie value, and the function to update it.
 */
export function useCookie(key, initialValue) {
  const [item, setInnerValue] = useState(() => {
    return Cookies.get(key) || initialValue;
  });

  /**
   * Set value of cookie
   * @param {Object|string} value 
   * @param {Cookies.CookieAttributes} [options]
   */
  const setValue = (value, options) => {
    setInnerValue(value);
    Cookies.set(key, value, options);
  };

  return [item, setValue];
}

export default useCookie;

usePrevious

Đây là hook giúp bạn lấy được giá trị trước đó của state và props trong React. Trước đây nếu chúng ta sử dụng Class Component thì có thể sử dụng componentDidUpdate, còn với Functional Component, chúng ta sử dụng useRef để lưu lại giá trị props và state trước đó

function usePrevious(value) {
  // Với ref, ta có thể lưu trữ bất kỳ giá trị nào, tương tự với  việc thể hiện 1 instance của 1 lớp
  const ref = useRef();

  // lưu giữ giá trị hiện tại vào trong ref
  useEffect(() => {
    ref.current = value;
  }, [value]); // Chỉ re-render khi giá trị thay đổi

  // trả về giá trị trước đó
  return ref.current;
}

useFetch

Mỗi khi cần call API get dữ liệu từ server mà không cần đẩy vào Redux hoặc 1 state management nào khác thì mình thường sử dụng hook này cho nhanh và tiện.

import { useState, useEffect } from "react";

export default function useFetch(url, options) {
  const [data, setData] = useState([]);
  const [error, setError] = useState(null);

  useEffect(() => {
    const fetchData = async () => {
      try {
        const resp = await fetch(url, options);
        const res = await resp.json();
        if (isMounted) setData(res.data);
      } catch (e) {
        if (isMounted) setData([]);
        if (isMounted) setError(e);
      }
    };

    let isMounted = true;
    fetchData();
    return () => {
      isMounted = false;
    };
  }, []);

  return { data, error };
}

Kết bài

Trong quá trình làm dự án thì có rất nhiều tính năng mà bạn có thể viết lại thành 1 custom hook. Trên đây chỉ là vài custom hook cơ bản mà hầu như dự án React nào mình cũng sử dụng. Hy vọng bài viết hữu ích dành cho các bạn, cảm ơn các bạn đã đọc và theo dõi. Hẹn gặp lại các bạn trong các bài viết tiếp theo của mình.

Bạn có thể tham khảo những nhiệm vụ và yêu cầu của lập trình viên ReactJS thông qua hàng loạt việc làm ReactJS trên TopDev.

Tác giả: Phạm Minh Khoa

Xem thêm:

Thủ thuật xử lý lỗi trong Golang

AngularJS Là Gì? Khác Biệt Nào Giữa Angular Và Frontend Framework Khác

Tối ưu ứng dụng React bằng Code-Spliting