mishig HF Staff commited on
Commit
1a13cb6
·
verified ·
1 Parent(s): cc81842

Sync from GitHub via hub-sync

Browse files
src/app/[org]/[dataset]/[episode]/episode-viewer.tsx CHANGED
@@ -1,13 +1,6 @@
1
  "use client";
2
 
3
- import {
4
- useState,
5
- useEffect,
6
- useRef,
7
- lazy,
8
- Suspense,
9
- useCallback,
10
- } from "react";
11
  import { useRouter, useSearchParams } from "next/navigation";
12
  import { postParentMessageWithParams } from "@/utils/postParentMessage";
13
  import { SimpleVideosPlayer } from "@/components/simple-videos-player";
@@ -470,33 +463,52 @@ function EpisodeViewerInner({
470
  });
471
  }, []);
472
 
473
- const handleKeyDown = useCallback(
474
- (e: KeyboardEvent) => {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
475
  const { key } = e;
 
476
 
477
  if (key === " ") {
478
  e.preventDefault();
479
- if (activeTab === "urdf") {
480
  urdfPlayToggleRef.current?.();
481
  } else {
482
  setIsPlaying((prev: boolean) => !prev);
483
  }
484
  } else if (key === "ArrowDown" || key === "ArrowUp") {
485
  e.preventDefault();
486
- if (activeTab === "urdf") {
487
  const nextEp =
488
- key === "ArrowDown" ? urdfEpisode + 1 : urdfEpisode - 1;
489
- const lowest = episodes[0];
490
- const highest = episodes[episodes.length - 1];
491
  if (nextEp >= lowest && nextEp <= highest) {
492
  setUrdfEpisode(nextEp);
493
  urdfChangerRef.current?.(nextEp);
494
  }
495
  } else {
496
  const nextEpisodeId =
497
- key === "ArrowDown" ? episodeId + 1 : episodeId - 1;
498
- const lowestEpisodeId = episodes[0];
499
- const highestEpisodeId = episodes[episodes.length - 1];
500
  if (
501
  nextEpisodeId >= lowestEpisodeId &&
502
  nextEpisodeId <= highestEpisodeId
@@ -505,24 +517,12 @@ function EpisodeViewerInner({
505
  }
506
  }
507
  }
508
- },
509
- [activeTab, episodeId, episodes, router, setIsPlaying, urdfEpisode],
510
- );
511
-
512
- // Initialize based on URL time parameter
513
- useEffect(() => {
514
- // Initialize page based on current episode
515
- const episodeIndex = episodes.indexOf(episodeId);
516
- if (episodeIndex !== -1) {
517
- setCurrentPage(Math.floor(episodeIndex / pageSize) + 1);
518
- }
519
-
520
- // Add keyboard event listener
521
- window.addEventListener("keydown", handleKeyDown);
522
- return () => {
523
- window.removeEventListener("keydown", handleKeyDown);
524
  };
525
- }, [episodes, episodeId, pageSize, handleKeyDown]);
 
 
 
 
526
 
527
  // Pagination functions
528
  const nextPage = () => {
 
1
  "use client";
2
 
3
+ import { useState, useEffect, useRef, lazy, Suspense } from "react";
 
 
 
 
 
 
 
4
  import { useRouter, useSearchParams } from "next/navigation";
5
  import { postParentMessageWithParams } from "@/utils/postParentMessage";
6
  import { SimpleVideosPlayer } from "@/components/simple-videos-player";
 
463
  });
464
  }, []);
465
 
466
+ // Initialize page based on the current episode. Splitting this out from
467
+ // the keyboard listener effect lets the listener attach exactly once.
468
+ useEffect(() => {
469
+ const episodeIndex = episodes.indexOf(episodeId);
470
+ if (episodeIndex !== -1) {
471
+ setCurrentPage(Math.floor(episodeIndex / pageSize) + 1);
472
+ }
473
+ }, [episodes, episodeId, pageSize]);
474
+
475
+ // Mirror the values the keydown handler needs into a ref. Without this,
476
+ // `useCallback` would produce a new handler whenever `activeTab` /
477
+ // `episodeId` / `urdfEpisode` changed, and the keydown effect would
478
+ // detach + reattach the listener each time. Now the listener attaches
479
+ // once and reads the latest state via the ref.
480
+ // Vercel rule: advanced-event-handler-refs.
481
+ const keyStateRef = useRef({ activeTab, episodeId, episodes, urdfEpisode });
482
+ keyStateRef.current = { activeTab, episodeId, episodes, urdfEpisode };
483
+
484
+ useEffect(() => {
485
+ const onKeyDown = (e: KeyboardEvent) => {
486
  const { key } = e;
487
+ const s = keyStateRef.current;
488
 
489
  if (key === " ") {
490
  e.preventDefault();
491
+ if (s.activeTab === "urdf") {
492
  urdfPlayToggleRef.current?.();
493
  } else {
494
  setIsPlaying((prev: boolean) => !prev);
495
  }
496
  } else if (key === "ArrowDown" || key === "ArrowUp") {
497
  e.preventDefault();
498
+ if (s.activeTab === "urdf") {
499
  const nextEp =
500
+ key === "ArrowDown" ? s.urdfEpisode + 1 : s.urdfEpisode - 1;
501
+ const lowest = s.episodes[0];
502
+ const highest = s.episodes[s.episodes.length - 1];
503
  if (nextEp >= lowest && nextEp <= highest) {
504
  setUrdfEpisode(nextEp);
505
  urdfChangerRef.current?.(nextEp);
506
  }
507
  } else {
508
  const nextEpisodeId =
509
+ key === "ArrowDown" ? s.episodeId + 1 : s.episodeId - 1;
510
+ const lowestEpisodeId = s.episodes[0];
511
+ const highestEpisodeId = s.episodes[s.episodes.length - 1];
512
  if (
513
  nextEpisodeId >= lowestEpisodeId &&
514
  nextEpisodeId <= highestEpisodeId
 
517
  }
518
  }
519
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  };
521
+
522
+ window.addEventListener("keydown", onKeyDown);
523
+ return () => window.removeEventListener("keydown", onKeyDown);
524
+ // router / setIsPlaying are stable; the rest is read via keyStateRef.
525
+ }, [router, setIsPlaying]);
526
 
527
  // Pagination functions
528
  const nextPage = () => {