From 15760d6430f851b986de2c06375775b9e4eb6b36 Mon Sep 17 00:00:00 2001 From: dwindown Date: Sun, 4 Jan 2026 11:39:39 +0700 Subject: [PATCH] Fix React error #310 by ensuring hooks are called before conditional returns MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Moved useMemo calls before early returns in VideoPlayer component - This ensures hooks are always called in the same order on every render - Fixed violation of Rules of Hooks that caused error in production 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/pages/Bootcamp.tsx | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/pages/Bootcamp.tsx b/src/pages/Bootcamp.tsx index f112da2..5436159 100644 --- a/src/pages/Bootcamp.tsx +++ b/src/pages/Bootcamp.tsx @@ -155,6 +155,16 @@ const VideoPlayer = ({ // Memoize video source to prevent unnecessary re-renders const video = useMemo(getVideoSource, [lesson.id, lesson.video_host, lesson.m3u8_url, lesson.mp4_url, lesson.youtube_url, lesson.video_url, lesson.embed_code]); + // Determine video type - must be computed before conditional returns + const isYouTube = video?.type === 'youtube'; + const isAdilo = video?.type === 'adilo'; + const isEmbed = video?.type === 'embed'; + + // Memoize URL values BEFORE any conditional returns (Rules of Hooks) + const videoUrl = useMemo(() => (isYouTube ? video?.url : undefined), [isYouTube, video?.url]); + const m3u8Url = useMemo(() => (isAdilo ? video?.m3u8Url : undefined), [isAdilo, video?.m3u8Url]); + const mp4Url = useMemo(() => (isAdilo ? video?.mp4Url : undefined), [isAdilo, video?.mp4Url]); + // Show warning if no video available if (!video) { return ( @@ -168,7 +178,7 @@ const VideoPlayer = ({ } // Render based on video type - if (video.type === 'embed') { + if (isEmbed) { return (
@@ -187,15 +197,6 @@ const VideoPlayer = ({ ); } - // Adilo or YouTube with chapters support - const isYouTube = video.type === 'youtube'; - const isAdilo = video.type === 'adilo'; - - // Memoize URL values to ensure they're stable across renders - const videoUrl = useMemo(() => (isYouTube ? video.url : undefined), [isYouTube, video.url]); - const m3u8Url = useMemo(() => (isAdilo ? video.m3u8Url : undefined), [isAdilo, video.m3u8Url]); - const mp4Url = useMemo(() => (isAdilo ? video.mp4Url : undefined), [isAdilo, video.mp4Url]); - return ( <> {/* Video Player - Full Width */}