Chuyển tới nội dung chính

Hooks (@vppos/core/hooks)

Tất cả shared hooks import từ @vppos/core/hooks.

import {
useDebounce,
useStoreSelection,
usePermission,
useInfiniteScrollObserver,
} from "@vppos/core/hooks";

Danh sách hooks

useDebounce(value, delay)

Debounce một giá trị. Dùng cho search input.

const [search, setSearch] = useState("");
const debouncedSearch = useDebounce(search, 300);

// debouncedSearch chỉ cập nhật sau 300ms không gõ thêm
cảnh báo

Không dùng setTimeout thủ công. Luôn dùng useDebounce.

useStoreSelection()

Lấy thông tin cửa hàng đang chọn. Reactive — component re-render khi thay đổi.

const { storeId, selectedStore } = useStoreSelection();
cảnh báo

Không dùng getSelectedStoreId() trong component — chỉ dành cho logic ngoài React.

usePermission()

Kiểm tra quyền user hiện tại.

useColumnSettings(tableKey)

Quản lý cấu hình hiển thị cột table, persist vào localStorage.

useBrandInitializer()

Khởi tạo brand config cho cửa hàng.

useMediaQuery(query)

CSS media query responsive.

useDateRangeFilter()

Quản lý state cho filter date range (start/end date).

useInfiniteScrollObserver(options)

Hook headless để bắt sự kiện chạm đáy bằng IntersectionObserver và gọi onLoadMore. Phù hợp cho dropdown/list/custom UI cần load thêm dữ liệu theo trang.

const { sentinelRef } = useInfiniteScrollObserver({
enabled: true,
hasMore,
isLoading: isLoadingMore,
onLoadMore: handleLoadMore,
rootMargin: "120px",
});

return (
<div className="max-h-72 overflow-auto">
{items.map((item) => (
<Row key={item.id} item={item} />
))}
<div ref={sentinelRef} />
</div>
);

Dùng cái nào khi làm infinite scroll?

  • Dùng InfiniteScroll component (@vppos/core/ui/react) khi bạn muốn triển khai nhanh, UI chuẩn sẵn (loader/end message/sentinel).
  • Dùng useInfiniteScrollObserver hook khi bạn cần custom layout phức tạp (dropdown riêng, virtual list, container đặc biệt).

Pattern khuyến nghị (Select / UI filters)

  1. Giữ query state ở page/component.
  2. Debounce query bằng useDebounce.
  3. Gọi API theo query + page.
  4. Dùng infinite scroll để tăng page khi chạm đáy.
const [query, setQuery] = useState("");
const [page, setPage] = useState(1);
const debouncedQuery = useDebounce(query, 300);

const { data, isFetching } = useGetServicePlansQuery({
page,
limit: 20,
search: debouncedQuery || undefined,
});

const hasMore = (data?.pagination?.page ?? 1) < (data?.pagination?.total_pages ?? 1);

const loadMore = () => {
if (!isFetching && hasMore) {
setPage((prev) => prev + 1);
}
};