- vừa được xem lúc

Làm thế nào để tối ưu hóa API Calls trong Ứng dụng React lên đến 40%

0 0 4

Người đăng: Vũ Tuấn

Theo Viblo Asia

Là lập trình viên React, chúng ta thường gặp phải những trường hợp cần đồng bộ hóa nhiều thay đổi trạng thái nhanh chóng với API. Việc thực hiện gọi API cho mỗi thay đổi nhỏ có thể không hiệu quả và gây quá tải cho cả client và server. Đây là lúc kỹ thuật debouncing và quản lý trạng thái thông minh phát huy tác dụng. Trong bài viết này, chúng ta sẽ xây dựng một hook React tùy chỉnh để nắm bắt các lệnh gọi cập nhật API song song bằng cách hợp nhất payloads và debounce lệnh gọi API.

Vấn đề đang gặp phải

Hãy tưởng tượng một trường nhập liệu, nơi người dùng có thể điều chỉnh cài đặt hoặc tùy chọn. Mỗi lần nhấn phím hoặc điều chỉnh có thể kích hoạt một lệnh gọi API để lưu trạng thái mới. Nếu người dùng thực hiện một số thay đổi liên tiếp nhanh chóng, điều này có thể dẫn đến một loạt yêu cầu API:

  • Sử dụng tài nguyên mạng không hiệu quả.
  • Tiềm ẩn race conditions.
  • Tải không cần thiết trên máy chủ.

Giải pháp: Debouncing và useRef

1. Debouncing

Debouncing là một kỹ thuật được sử dụng để giới hạn tốc độ kích hoạt của một hàm. Thay vì gọi hàm ngay lập tức, bạn đợi một khoảng thời gian không hoạt động nhất định trước khi thực thi nó. Nếu một lệnh gọi khác đến trước khi hết thời gian chờ, bộ hẹn giờ sẽ được đặt lại.

Tại sao nên sử dụng Debouncing?

  • Cải thiện hiệu suất: Giảm số lượng lệnh gọi API không cần thiết.
  • Tối ưu hóa tài nguyên: Giảm thiểu tải máy chủ và mức sử dụng mạng.
  • Nâng cao trải nghiệm người dùng: Ngăn chặn tình trạng lag và lỗi tiềm ẩn do các lệnh gọi liên tiếp, nhanh chóng.

2. Sử dụng useRef

Trong React, useRef là một hook cho phép bạn duy trì các giá trị có thể thay đổi giữa các lần render mà không kích hoạt re-render. Về cơ bản, nó là một container chứa một giá trị có thể thay đổi.

Tại sao nên sử dụng useRef ở đây?

  • Duy trì các bản cập nhật tích lũy: Chúng ta cần theo dõi các bản cập nhật tích lũy giữa các lần render mà không gây ra re-render.
  • Truy cập giá trị hiện tại có thể thay đổi: useRef cung cấp cho chúng ta một thuộc tính .current mà chúng ta có thể đọc và ghi.

Xây dựng Hook useDebouncedUpdate

Hãy đi sâu vào mã và tìm hiểu cách tất cả kết hợp với nhau thông qua một ví dụ dưới đây:

import { debounce } from "@mui/material";
import { useCallback, useEffect, useRef } from "react"; type DebouncedUpdateParams = { id: string; params: Record<string, any>;
}; function useDebouncedUpdate( apiUpdate: (params: DebouncedUpdateParams) => void, delay: number = 300, ) { const accumulatedUpdates = useRef<DebouncedUpdateParams | null>(null); const processUpdates = useRef( debounce(() => { if (accumulatedUpdates.current) { apiUpdate(accumulatedUpdates.current); accumulatedUpdates.current = null; } }, delay), ).current; const handleUpdate = useCallback( (params: DebouncedUpdateParams) => { accumulatedUpdates.current = { id: params.id, params: { ...(accumulatedUpdates.current?.params || {}), ...params.params, }, }; processUpdates(); }, [processUpdates], ); useEffect(() => { return () => { processUpdates.clear(); }; }, [processUpdates]); return handleUpdate;
} export default useDebouncedUpdate;

Chúng ta hãy cùng phân tích ví dụ trên.

1. Tích lũy bản cập nhật với useRef

Chúng ta khởi tạo một useRef được gọi là accumulatedUpdates để lưu trữ các tham số được kết hợp của tất cả các bản cập nhật đến.

const accumulatedUpdates = useRef<DebouncedUpdateParams | null>(null);

2. Debounce lệnh gọi API

Chúng ta tạo một hàm debounced processUpdates bằng cách sử dụng tiện ích debounce từ Material UI.

const processUpdates = useRef( debounce(() => { if (accumulatedUpdates.current) { apiUpdate(accumulatedUpdates.current); accumulatedUpdates.current = null; } }, delay),
).current;

Tại sao lại dùng useRef cho processUpdates? Chúng ta sử dụng useRef để đảm bảo rằng hàm debounced không được tạo lại trên mỗi lần render, điều này sẽ đặt lại bộ hẹn giờ debounce.

3. Xử lý bản cập nhật với useCallback

Hàm handleUpdate chịu trách nhiệm tích lũy các bản cập nhật và kích hoạt lệnh gọi API debounced.

const handleUpdate = useCallback( (params: DebouncedUpdateParams) => { accumulatedUpdates.current = { id: params.id, params: { ...(accumulatedUpdates.current?.params || {}), ...params.params, }, }; processUpdates(); }, [processUpdates],
);
  • Hợp nhất Params: Chúng ta hợp nhất các tham số mới với bất kỳ tham số hiện có nào để đảm bảo tất cả các bản cập nhật được ghi lại.
  • Kích hoạt Debounce: Mỗi khi handleUpdate được gọi, chúng ta kích hoạt processUpdates(), nhưng lệnh gọi API thực tế bị debounced.

4. Dọn dẹp với useEffect

Chúng ta xóa hàm debounced khi component unmount để ngăn chặn rò rỉ bộ nhớ.

useEffect(() => { return () => { processUpdates.clear(); };
}, [processUpdates]);

Vậy thì rốt cuộc ví dụ ban đầu ở trên hoạt động như thế nào?

  • Tích lũy tham số: Mỗi bản cập nhật thêm các tham số của nó vào accumulatedUpdates.current, hợp nhất với bất kỳ tham số hiện có nào.
  • Thực thi Debounce: processUpdates đợi delay mili giây không hoạt động trước khi thực thi.
  • Gọi API: Sau khi thời gian debounced trôi qua, apiUpdate được gọi với các tham số được hợp nhất.
  • Đặt lại bản cập nhật tích lũy: Sau khi gọi API, chúng ta đặt lại accumulatedUpdates.current thành null.

Ví dụ sử dụng Dưới đây là cách bạn có thể sử dụng hook này trong một component:

import React from "react";
import useDebouncedUpdate from "./useDebouncedUpdate"; function SettingsComponent() { const debouncedUpdate = useDebouncedUpdate(updateSettingsApi, 500); const handleChange = (settingName, value) => { debouncedUpdate({ id: "user-settings", params: { [settingName]: value }, }); }; return ( <div> <input type="text" onChange={(e) => handleChange("username", e.target.value)} /> <input type="checkbox" onChange={(e) => handleChange("notifications", e.target.checked)} /> </div> );
} function updateSettingsApi({ id, params }) { // Make your API call here console.log("Updating settings:", params);
}
  • Hành động của người dùng: Khi người dùng nhập hoặc chuyển đổi cài đặt, handleChange được gọi.
  • Bản cập nhật Debounced: Các thay đổi được tích lũy và gửi đến API sau 500ms không hoạt động.

Kết luận

Hook này là giải pháp cho một thách thức mà chúng tôi gặp phải trong dự án của mình. Trong trình chỉnh sửa trực quan, khi bạn di chuyển xung quanh canvas, nó sẽ kích hoạt các yêu cầu đồng thời để cập nhật cả offset và mức thu phóng. Điều này cho phép chúng tôi không chỉ gửi một yêu cầu thay vì hai yêu cầu mà còn debounce các bản cập nhật vì sự kiện chuột được kích hoạt nhiều lần.

Bằng cách kết hợp debouncing với tích lũy trạng thái, chúng ta có thể tạo ra các ứng dụng hiệu quả và phản hồi nhanh. Hook useDebouncedUpdate đảm bảo rằng các thay đổi nhanh chóng được gom lại với nhau, giảm các lệnh gọi API không cần thiết và cải thiện hiệu suất. Cảm ơn các bạn đã theo dõi.

Bình luận

Bài viết tương tự

- vừa được xem lúc

Tìm hiểu về Redux Thunk

Chào mọi người, nếu bạn là người đã biết về React và đang làm quen với Redux chắc hẳn bạn đang rất mơ hồ về các khái niệm cơ bản của Redux như dispatch, store, action creator,... bạn còn đang vật lộn với đống document của Redux để hiểu những khái niệm đó và bạn nghe ai đó trong team nói về Redux Thu

0 0 399

- vừa được xem lúc

[React] Giới thiệu tổng quát về Redux Toolkit

1. Redux Toolkit (RTK) là gì và tại sao lại có nó. . .

0 0 6.6k

- vừa được xem lúc

Uống Pepsi code Vue đi - Uống Cocacola code React nha ;)

. (Nguồn ảnh: Internet). Chào các bạn, chào các bạn. Let's go . 1.

0 0 146

- vừa được xem lúc

Cài đặt taillwind css cho dự án React

Trong bài viết cùng mình tìm hiểu cách cài đặt tailwind css cho một dự án React sẵn có. .

0 0 146

- vừa được xem lúc

Formik vs React Hook Form (Phần 1)

Các lập trình viên Front End đều làm việc rất nhiều với form cùng sự phức tạp của ứng dụng. Do vậy chúng ta cần những thư viện form mạnh mẽ hỗ trợ quản lý các form state, form validation... Thành phần module. Formik bao gồm có 9 dependencies khác. . React Hook Form thì không có.

0 0 371

- vừa được xem lúc

Hướng dẫn React Redux cho người mới bắt đầu - Phần 1

Lời mởi đầu. Chào các bạn, ở thời điểm thực hiện bài viết này mình cũng là một người đang bắt đầu tìm hiểu và học với ReactJs và Redux, trong quá trình tìm hiểu đọc các tài liệu về thư viện này mình có tìm được một bài hướng dẫn khá hay nên đã quyết định chia sẻ với mọi người .

0 0 280