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()​

Hook đồng bộ với localStorage, cung cấp các hàm kiểm tra quyền truy cập module, quyền action chi tiết, và role hiện tại. Dùng ở mọi nơi trong MFE.

const { isSuperAdmin, isAdmin, isUser, can, canAll, canAny, hasModule } = usePermission();

// Role checks
if (isSuperAdmin) {
/* ... */
}

// Permission checks (Action)
can("products.delete"); // Trả về true nếu có quyền, superadmin/admin luôn true
canAll("products.edit", "products.delete"); // Phải có TẤT CẢ các quyền
canAny("products.edit", "products.view"); // Có ÍT NHẤT 1 quyền

// Module checks (View)
hasModule("inventory.products"); // Trả về true nếu có quyền truy cập module

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