From a1bdfece6d98b5c32aa0af932fce91de54549a6a Mon Sep 17 00:00:00 2001 From: npeter83 Date: Sat, 18 Jul 2026 02:19:52 +0200 Subject: [PATCH] refactor(nav): read navigation from context, drop the prop-drilling VideoCard/PlayerModal read openChannel from useNavigationActions (the memo'd VideoCard subscribes to the STABLE actions context, so a page/channel change no longer re-renders it); NavSidebar/Header read page/setPage; ChannelPage reads closeChannel; NotificationsPanel reads setPage. App sheds the matching props, and Feed/VirtualFeed no longer thread onOpenChannel at all. --- frontend/src/App.tsx | 11 ++--------- frontend/src/components/ChannelPage.tsx | 9 +++------ frontend/src/components/Feed.tsx | 15 --------------- frontend/src/components/Header.tsx | 8 +++----- frontend/src/components/NavSidebar.tsx | 7 +++---- frontend/src/components/NotificationsPanel.tsx | 5 ++--- frontend/src/components/PlayerModal.tsx | 9 ++++----- frontend/src/components/VideoCard.tsx | 6 +++--- frontend/src/components/VirtualFeed.tsx | 3 --- 9 files changed, 20 insertions(+), 53 deletions(-) diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 19dbe46..4c649dc 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -148,7 +148,7 @@ function loadInitialFilters(): FeedFilters { export default function App() { const { t, i18n } = useTranslation(); const { page, channelView, ytSearch } = useNavigation(); - const { setPage, openChannel, closeChannel, enterYtSearch, exitYtSearch } = useNavigationActions(); + const { setPage, openChannel, enterYtSearch, exitYtSearch } = useNavigationActions(); const [theme, setThemeState] = useState(() => loadLocalTheme()); const [filters, setFiltersState] = useState(loadInitialFilters); // Whether this load arrived via a "Share view" link (captured once, before the URL is stripped) @@ -636,8 +636,6 @@ export default function App() {
setAboutOpen(true)} onChangeLanguage={changeLanguage} language={i18n.language as LangCode} @@ -699,8 +697,6 @@ export default function App() { me={meQuery.data!} view={view} setView={setView} - onBack={closeChannel} - onOpenChannel={openChannel} onShowInFeed={() => { // Keep the rest of the feed's filters — the point is "this channel, the way I // normally read": unwatched, my tags, my date window. @@ -730,8 +726,6 @@ export default function App() { setChannelsSearch={setChannelsSearch} playlistsSearch={playlistsSearch} setPlaylistsSearch={setPlaylistsSearch} - page={page} - setPage={setPage} onYtSearch={enterYtSearch} onGoToFullHistory={() => { setChannelFilter("needs_full"); @@ -789,7 +783,7 @@ export default function App() { setSelectedId={setSelectedPlaylistId} /> ) : page === "notifications" ? ( - + ) : page === "messages" && !meQuery.data!.is_demo ? (
@@ -826,7 +820,6 @@ export default function App() { ytSearch={ytSearch} onYtSearch={enterYtSearch} onExitYtSearch={exitYtSearch} - onOpenChannel={openChannel} /> )} diff --git a/frontend/src/components/ChannelPage.tsx b/frontend/src/components/ChannelPage.tsx index 67162cf..4c76763 100644 --- a/frontend/src/components/ChannelPage.tsx +++ b/frontend/src/components/ChannelPage.tsx @@ -1,6 +1,7 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useNavigationActions } from "./NavigationProvider"; import { ArrowLeft, Ban, Check, ExternalLink, Loader2, Plus, RefreshCw, SlidersHorizontal } from "lucide-react"; import Avatar from "./Avatar"; import Feed from "./Feed"; @@ -57,8 +58,6 @@ export default function ChannelPage({ me, view, setView, - onBack, - onOpenChannel, onShowInFeed, }: { channelId: string; @@ -68,14 +67,13 @@ export default function ChannelPage({ // toolbar carries the same switcher and a change here is the same account-wide choice. view: FeedView; setView: (v: FeedView) => void; - onBack: () => void; // Narrow the real feed to this channel and go there. Offered only for a channel you're // subscribed to: the feed defaults to scope "my", so filtering it to a channel you don't // follow would just land you on an empty page. onShowInFeed: () => void; - onOpenChannel: (id: string, name?: string) => void; }) { const { t, i18n } = useTranslation(); + const { closeChannel } = useNavigationActions(); const qc = useQueryClient(); const confirm = useConfirm(); const [tab, setTab] = useState<"videos" | "about">("videos"); @@ -245,7 +243,7 @@ export default function ChannelPage({ )}