@adventurelabs/scout-core 1.4.25 → 1.4.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -417,9 +417,10 @@ const feedCursorEq = (a, b) => {
417
417
  export const useInfiniteFeedByHerd = (herdId, options) => {
418
418
  const [pages, setPages] = useState([]);
419
419
  const [currentCursor, setCurrentCursor] = useState(null);
420
+ // Match dummy: use state so hasMore/nextCursor trigger re-renders and loadMore sees latest (ref was not updating UI)
421
+ const [lastResult, setLastResult] = useState(null);
420
422
  const prevHerdIdRef = useRef(undefined);
421
423
  const lastAddedCursorRef = useRef(undefined);
422
- const lastResultRef = useRef(null);
423
424
  const pagesLengthRef = useRef(0);
424
425
  const currentQuery = useGetFeedInfiniteByHerdQuery({
425
426
  herdId,
@@ -437,7 +438,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
437
438
  setPages([]);
438
439
  setCurrentCursor(null);
439
440
  lastAddedCursorRef.current = undefined;
440
- lastResultRef.current = null;
441
+ setLastResult(null);
441
442
  }
442
443
  prevHerdIdRef.current = herdId;
443
444
  }, [herdId]);
@@ -456,11 +457,13 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
456
457
  ? currentQuery.data.items
457
458
  : [];
458
459
  const limit = options.limit || 20;
459
- // Store hasMore/nextCursor from this response so loadMore can use it (like dummy's currentResult)
460
- lastResultRef.current = {
460
+ // Defer lastResult to next tick so consumer's IntersectionObserver is recreated
461
+ // after hasMore is true and its callback can fire (sentinel may already be in view).
462
+ const nextResult = {
461
463
  hasMore: currentQuery.data.hasMore ?? false,
462
464
  nextCursor: currentQuery.data.nextCursor ?? null,
463
465
  };
466
+ queueMicrotask(() => setLastResult(nextResult));
464
467
  setPages((prev) => {
465
468
  const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
466
469
  if (!existingPage) {
@@ -476,18 +479,17 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
476
479
  });
477
480
  }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
478
481
  const loadMore = useCallback(() => {
479
- const result = lastResultRef.current;
480
- if (result?.hasMore &&
481
- result.nextCursor != null &&
482
+ if (lastResult?.hasMore &&
483
+ lastResult.nextCursor != null &&
482
484
  !currentQuery.isLoading) {
483
- setCurrentCursor(result.nextCursor);
485
+ setCurrentCursor(lastResult.nextCursor);
484
486
  }
485
- }, [currentQuery.isLoading]);
487
+ }, [lastResult, currentQuery.isLoading]);
486
488
  const refetch = useCallback(() => {
487
489
  setPages([]);
488
490
  setCurrentCursor(null);
489
491
  lastAddedCursorRef.current = undefined;
490
- lastResultRef.current = null;
492
+ setLastResult(null);
491
493
  currentQuery.refetch();
492
494
  }, [currentQuery]);
493
495
  const allItems = useMemo(() => {
@@ -504,7 +506,7 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
504
506
  items: allItems,
505
507
  isLoading: currentQuery.isLoading && pages.length === 0,
506
508
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
507
- hasMore: (lastResultRef.current?.hasMore ??
509
+ hasMore: (lastResult?.hasMore ??
508
510
  (currentCursor !== null && pages.length > 0)) ??
509
511
  false,
510
512
  loadMore,
@@ -515,9 +517,9 @@ export const useInfiniteFeedByHerd = (herdId, options) => {
515
517
  export const useInfiniteFeedByDevice = (deviceId, options) => {
516
518
  const [pages, setPages] = useState([]);
517
519
  const [currentCursor, setCurrentCursor] = useState(null);
520
+ const [lastResult, setLastResult] = useState(null);
518
521
  const prevDeviceIdRef = useRef(undefined);
519
522
  const lastAddedCursorRef = useRef(undefined);
520
- const lastResultRef = useRef(null);
521
523
  const pagesLengthRef = useRef(0);
522
524
  const currentQuery = useGetFeedInfiniteByDeviceQuery({
523
525
  deviceId,
@@ -535,7 +537,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
535
537
  setPages([]);
536
538
  setCurrentCursor(null);
537
539
  lastAddedCursorRef.current = undefined;
538
- lastResultRef.current = null;
540
+ setLastResult(null);
539
541
  }
540
542
  prevDeviceIdRef.current = deviceId;
541
543
  }, [deviceId]);
@@ -549,6 +551,11 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
549
551
  if (pagesLengthRef.current > 0 &&
550
552
  feedCursorEq(lastAddedCursorRef.current ?? null, currentCursor))
551
553
  return;
554
+ const nextResult = {
555
+ hasMore: currentQuery.data?.hasMore ?? false,
556
+ nextCursor: currentQuery.data?.nextCursor ?? null,
557
+ };
558
+ queueMicrotask(() => setLastResult(nextResult));
552
559
  setPages((prev) => {
553
560
  const existingPage = prev.find((p) => feedCursorEq(p.cursor, currentCursor));
554
561
  if (!existingPage) {
@@ -559,10 +566,6 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
559
566
  if (items.length >= limit) {
560
567
  lastAddedCursorRef.current = currentCursor;
561
568
  }
562
- lastResultRef.current = {
563
- hasMore: currentQuery.data?.hasMore ?? false,
564
- nextCursor: currentQuery.data?.nextCursor ?? null,
565
- };
566
569
  return [
567
570
  ...prev,
568
571
  { cursor: currentCursor, data: items },
@@ -572,18 +575,17 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
572
575
  });
573
576
  }, [currentQuery.data, currentQuery.isLoading, currentCursor, pages.length, options.limit]);
574
577
  const loadMore = useCallback(() => {
575
- const result = lastResultRef.current;
576
- if (result?.hasMore &&
577
- result.nextCursor != null &&
578
+ if (lastResult?.hasMore &&
579
+ lastResult.nextCursor != null &&
578
580
  !currentQuery.isLoading) {
579
- setCurrentCursor(result.nextCursor);
581
+ setCurrentCursor(lastResult.nextCursor);
580
582
  }
581
- }, [currentQuery.isLoading]);
583
+ }, [lastResult, currentQuery.isLoading]);
582
584
  const refetch = useCallback(() => {
583
585
  setPages([]);
584
586
  setCurrentCursor(null);
585
587
  lastAddedCursorRef.current = undefined;
586
- lastResultRef.current = null;
588
+ setLastResult(null);
587
589
  currentQuery.refetch();
588
590
  }, [currentQuery]);
589
591
  const allItems = useMemo(() => {
@@ -600,7 +602,7 @@ export const useInfiniteFeedByDevice = (deviceId, options) => {
600
602
  items: allItems,
601
603
  isLoading: currentQuery.isLoading && pages.length === 0,
602
604
  isLoadingMore: currentQuery.isLoading && pages.length > 0,
603
- hasMore: (lastResultRef.current?.hasMore ??
605
+ hasMore: (lastResult?.hasMore ??
604
606
  (currentCursor !== null && pages.length > 0)) ??
605
607
  false,
606
608
  loadMore,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adventurelabs/scout-core",
3
- "version": "1.4.25",
3
+ "version": "1.4.28",
4
4
  "description": "Core utilities and helpers for Adventure Labs Scout applications",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",