From 7a196cedebbf9291f218a3d43d1bd0a43a3a6ae6 Mon Sep 17 00:00:00 2001 From: Innei Date: Fri, 26 Jul 2024 17:41:01 +0800 Subject: [PATCH] perf: reduce player re-render reduce cpu usage Signed-off-by: Innei --- src/renderer/src/atoms/player.ts | 1 + src/renderer/src/lib/jotai.ts | 7 +- .../src/modules/feed-column/corner-player.tsx | 138 ++++++++++-------- 3 files changed, 81 insertions(+), 65 deletions(-) diff --git a/src/renderer/src/atoms/player.ts b/src/renderer/src/atoms/player.ts index ce4f21179..694591e9d 100644 --- a/src/renderer/src/atoms/player.ts +++ b/src/renderer/src/atoms/player.ts @@ -29,6 +29,7 @@ export const [ useSetPlayerAtom, getPlayerAtomValue, setPlayerAtomValue, + usePlayerAtomSelector, ] = createAtomHooks( atomWithStorage( getStorageNS("player"), diff --git a/src/renderer/src/lib/jotai.ts b/src/renderer/src/lib/jotai.ts index 8d7d3b7c9..8dc105ebb 100644 --- a/src/renderer/src/lib/jotai.ts +++ b/src/renderer/src/lib/jotai.ts @@ -23,10 +23,12 @@ export const createAtomHooks = (atom: PrimitiveAtom) => () => useAtomValue(atom, options), () => useSetAtom(atom, options), ...createAtomAccessor(atom), + createAtomSelector(atom), ] as const -export const createAtomSelector = (atom: Atom) => { - const useHook = (selector: (a: T) => R, deps: any[] = []) => +const noop = [] +const createAtomSelector = (atom: Atom) => { + const useHook = (selector: (a: T) => R, deps: any[] = noop) => useAtomValue( selectAtom( atom, @@ -34,6 +36,5 @@ export const createAtomSelector = (atom: Atom) => { ), ) - useHook.__atom = atom return useHook } diff --git a/src/renderer/src/modules/feed-column/corner-player.tsx b/src/renderer/src/modules/feed-column/corner-player.tsx index a18249d84..0c104d26e 100644 --- a/src/renderer/src/modules/feed-column/corner-player.tsx +++ b/src/renderer/src/modules/feed-column/corner-player.tsx @@ -1,9 +1,11 @@ import * as Slider from "@radix-ui/react-slider" -import { Player, usePlayerAtomValue } from "@renderer/atoms/player" -import { FeedIcon } from "@renderer/components/feed-icon" import { - microReboundPreset, -} from "@renderer/components/ui/constants/spring" + Player, + usePlayerAtomSelector, + usePlayerAtomValue, +} from "@renderer/atoms/player" +import { FeedIcon } from "@renderer/components/feed-icon" +import { microReboundPreset } from "@renderer/components/ui/constants/spring" import { Tooltip, TooltipContent, @@ -22,28 +24,14 @@ const handleClickPlay = () => { } export const CornerPlayer = () => { - const playerValue = usePlayerAtomValue() + const entryId = usePlayerAtomSelector((v) => v.entryId) + const show = usePlayerAtomSelector((v) => v.show) + const status = usePlayerAtomSelector((v) => v.status) + const isMute = usePlayerAtomSelector((v) => v.isMute) + const playerValue = { entryId, show, status, isMute } const entry = useEntry(playerValue.entryId) const feed = useFeedById(entry?.feedId) - const { currentTime = 0, duration = 0 } = playerValue - const [controlledCurrentTime, setControlledCurrentTime] = - useState(currentTime) - const [isDraggingProgress, setIsDraggingProgress] = useState(false) - useEffect(() => { - if (isDraggingProgress) return - setControlledCurrentTime(currentTime) - }, [currentTime, isDraggingProgress]) - - const currentTimeIndicator = dayjs() - .startOf("y") - .second(controlledCurrentTime) - .format("mm:ss") - const remainingTimeIndicator = dayjs() - .startOf("y") - .second(duration - controlledCurrentTime) - .format("mm:ss") - return ( {playerValue.show && entry && feed && ( @@ -136,38 +124,7 @@ export const CornerPlayer = () => { {/* progress control */} -
-
-
{currentTimeIndicator}
-
- - - {remainingTimeIndicator} -
-
- - {/* slider */} - setIsDraggingProgress(true)} - onPointerUp={() => setIsDraggingProgress(false)} - onValueChange={(value) => setControlledCurrentTime(value[0])} - onValueCommit={(value) => Player.seek(value[0])} - > - - - - - {/* indicator */} - - -
+ @@ -176,6 +133,63 @@ export const CornerPlayer = () => { ) } +const PlayerProgress = () => { + const playerValue = usePlayerAtomValue() + + const { currentTime = 0, duration = 0 } = playerValue + const [controlledCurrentTime, setControlledCurrentTime] = + useState(currentTime) + const [isDraggingProgress, setIsDraggingProgress] = useState(false) + useEffect(() => { + if (isDraggingProgress) return + setControlledCurrentTime(currentTime) + }, [currentTime, isDraggingProgress]) + + const currentTimeIndicator = dayjs() + .startOf("y") + .second(controlledCurrentTime) + .format("mm:ss") + const remainingTimeIndicator = dayjs() + .startOf("y") + .second(duration - controlledCurrentTime) + .format("mm:ss") + + return ( +
+
+
{currentTimeIndicator}
+
+ - + {remainingTimeIndicator} +
+
+ + {/* slider */} + setIsDraggingProgress(true)} + onPointerUp={() => setIsDraggingProgress(false)} + onValueChange={(value) => setControlledCurrentTime(value[0])} + onValueCommit={(value) => Player.seek(value[0])} + > + + + + + {/* indicator */} + + +
+ ) +} + const ActionIcon = ({ className, onClick, @@ -204,7 +218,7 @@ const ActionIcon = ({ ) const VolumeSlider = () => { - const playerValue = usePlayerAtomValue() + const volume = usePlayerAtomSelector((v) => v.volume) return ( { max={1} step={0.01} orientation="vertical" - value={[playerValue.volume ?? 0.8]} + value={[volume ?? 0.8]} onValueChange={(value) => Player.setVolume(value[0])} > @@ -227,7 +241,7 @@ const VolumeSlider = () => { } const PlaybackRateSelector = () => { - const playerValue = usePlayerAtomValue() + const playbackRate = usePlayerAtomSelector((v) => v.playbackRate) return (
@@ -237,9 +251,9 @@ const PlaybackRateSelector = () => { type="button" className={cn( "center rounded-md font-mono hover:bg-theme-item-hover", - playerValue.playbackRate === rate && + playbackRate === rate && "bg-theme-item-hover text-black dark:text-white", - playerValue.playbackRate !== rate && "text-zinc-500", + playbackRate !== rate && "text-zinc-500", )} onClick={() => Player.setPlaybackRate(rate)} > @@ -252,9 +266,9 @@ const PlaybackRateSelector = () => { } const PlaybackRateButton = () => { - const playerValue = usePlayerAtomValue() + const playbackRate = usePlayerAtomSelector((v) => v.playbackRate) - const char = `${playerValue.playbackRate || 1}` + const char = `${playbackRate || 1}` return (