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
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();
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
InfiniteScrollcomponent (@vppos/core/ui/react) khi bạn muốn triển khai nhanh, UI chuẩn sẵn (loader/end message/sentinel). - Dùng
useInfiniteScrollObserverhook 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)
- Giữ
querystate ở page/component. - Debounce query bằng
useDebounce. - Gọi API theo
query + page. - Dùng infinite scroll để tăng
pagekhi 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);
}
};