Cách cải thiện khả năng tìm kiếm trong React bằng Debouncing

Trong React, khi triển khai chức năng tìm kiếm, trình xử lý onChange gọi hàm tìm kiếm mỗi lần người dùng nhập vào bên trong box đầu vào. Phương pháp này có thể gây lỗi hiệu suất, nhất là khi thực hiện gọi API hoặc truy vấn database.

Cách cải thiện khả năng tìm kiếm trong React bằng Debouncing

Những cuộc gọi thường xuyên tới hàm tìm kiếm có thể gây quá tải server web, khiến UI không phản hồi. Debouncing sẽ giải quyết vấn đề này.

Debouncing là gì?

Cụ thể, bạn triển khai hàm tìm kiếm trong React bằng cách gọi một hàm xử lý onChange trên mỗi lần gõ phím như sau:

import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    // Calls search function
    handleSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Trong khi code trên hoạt động, gọi backend để update kết quả tìm kiếm trên mỗi lần nhấn phím có thể tốn kém. Ví dụ, nếu bạn đang tìm “webdev”, ứng dụng sẽ gửi truy vấn tới backend với giá trị “w”, “we”, “web”,…

Debouncing là kỹ thuật hoạt động bằng cách trì hoãn chạy một hàm cho tới khi hết thời gian trễ. Hàm debounce phát hiện mỗi lần người dùng gõ phím và ngăn cuộc gọi tới trình xử lý tìm kiếm cho tới khi hết thời gian trễ. Nếu người dùng tiếp tục gõ trong thời gian trễ, đồng hồ bấm giờ được reset và React gọi lại hàm cho độ trễ mới. Quá trình này diễn ra liên tục cho tới khi người dùng tạm dừng gõ.

Bằng cách đợi người dùng tạm dừng gõ, debouncing đảm bảo ứng dụng chỉ thực hiện những truy vấn tìm kiếm cần thiết, từ đó, giảm tải server.

Cách debounce tìm kiếm trong React

Có một số thư viện mà bạn có thể dùng để triển khai debounce. Bạn cũng có thể chọn tự triển khai nó từ đầu bằng hàm setTimeout và clearTimeout của JavaScript.

Bài viết này dùng hàm debounce từ thư viện lodash. Giả sử bạn có sẵn một dự án React, tạo thành phần mới tên Search. Nếu chưa có dự án đang hoạt động, tạo app React bằng create-react-app.

Trong file thành phần Search, sao chép code sau để tạo box nhập tìm kiếm gọi hàm xử lý trên mỗi lần gõ phím.

import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    // Calls search function
    handleSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Để debounce hàm handleSearch, chuyển nó sang hàm debounce từ lodash.

import debounce from "lodash.debounce";
import { useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = () => {
    console.log("Search for:", searchTerm);
  };
  const debouncedSearch = debounce(handleSearch, 1000);

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    // Calls search function
    debouncedSearch();
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Trong hàm debounce, bạn đang chuyển sang hàm muốn trì hoãn, ví dụ: handleSearch, thời gian trì hoãn tính bằng mili giây, ví dụ: 500ms.

Trong khi code trên sẽ trì hoãn việc gọi truy vấn handleSearch cho tới khi người dùng tạm dừng gõ phím, nó không hoạt động trong React.

Debouncing và Rerender

Ứng dụng này dùng phương thức kiểm soát đầu vào. Điều đó có nghĩa giá trị trạng thái kiểm soát giá trị input. Mỗi lần người dùng nhập vào trường tìm kiếm, React update trạng thái này.

Trong React, khi thay đổi giá trị trạng thái, React hiện thành phần và triển khai tất cả hàm bên trong nó.

Ở thành phần tìm kiếm trên, khi hiển thị lại thành phần, React chạy hàm debounce. Hàm này tạo một đồng hồ bấm giờ mới, liên tục theo dõi độ trễ và đồng hồ bấm giờ cũ vẫn nằm trong bộ nhớ. Khi hết thời gian, nó kích hoạt tính năng tìm kiếm. Điều này có nghĩa hàm tìm kiếm không bao giờ được debounce, nó bị trễ khoảng 500ms. Chu kỳ này lặp lại trên mỗi lần render - hàm này tạo một đồng hồ bấm giờ mới, đồng hồ cũ hết hạn, rồi nó gọi hàm tìm kiếm.

Để hàm debounce hoạt động, bạn chỉ phải gọi nó một lần. Bạn có thể làm việc này bằng cách gọi hàm debounce bên ngoài thành phần hoặc bằng cách dùng kỹ thuật ghi nhớ. Bằng cách này, ngay cả khi thành phần này hiển thị, React sẽ không chạy lại nó.

Xác định hàm debounce bên ngoài thành phần tìm kiếm

Di chuyển hàm debounce bên ngoài thành phần tìm kiếm như bên dưới:

import debounce from "lodash.debounce"

const handleSearch = (searchTerm) => {
  console.log("Search for:", searchTerm);
};

const debouncedSearch = debounce(handleSearch, 500);

Giờ trong thành phần Search, gọi debouncedSearch và chuyển nó cụm tìm kiếm vào.

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    // Calls search function
    debouncedSearch(searchTerm);
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}

Hàm tìm kiếm này sẽ chỉ được gọi sau khi giai đoạn trễ kết thúc.

Memoizing hàm Debounce

Memoizing đề cập tới việc lưu kết quả của một hàm và tái sử dụng chúng khi bạn gọi hàm có cùng đối số.

Để memoize hàm debounce, dùng hook useMemo.

import debounce from "lodash.debounce";
import { useCallback, useMemo, useState } from "react";

export default function Search() {
  const [searchTerm, setSearchTerm] = useState("");

  const handleSearch = useCallback((searchTerm) => {
    console.log("Search for:", searchTerm);
  }, []);

  const debouncedSearch = useMemo(() => {
    return debounce(handleSearch, 500);
  }, [handleSearch]);

  const handleChange = (e) => {
    setSearchTerm(e.target.value);
    // Calls search function
    debouncedSearch(searchTerm);
  };

  return (
    <input
      onChange={handleChange}
      value={searchTerm}
      placeholder="Search here..."
    />
  );
}
Lưu ý rằng bạn cũng bao bọc hàm handleSearch trong hook useCallback để đảm bảo React chỉ gọi nó một lần. Nếu không có hook useCallback, React sẽ chạy hàm handleSearch với mỗi lần kết xuất lại, làm cho các phần phụ thuộc của hook useMemo thay đổi, từ đó sẽ gọi hàm debounce.

Giờ, React sẽ chỉ gọi hàm debounce nếu handleSearch hoặc thời gian trễ thay đổi.

Tóm lại, debounce sẽ giúp lập trình viên giảm truy vấn tới server vì nó chỉ gửi truy vấn sau khi hết thời gian trễ và người dùng đã tạm dừng gõ phím. Nhờ đó, server không bị quá tải và hiệu suất của ứng dụng được cải thiện.

CÓ THỂ BẠN QUAN TÂM