refactor: prevent unnecessary prop drilling

Components throughout the tree are anyways utilizing the zustand store,
so there is no reason to send props for the same store methods.
This commit is contained in:
talksik
2026-03-12 10:07:56 -07:00
parent 0265dbdac4
commit 5ce61d06b2
3 changed files with 22 additions and 17 deletions
@@ -8,7 +8,6 @@ import { useAudioSource } from "@/components/audio/use-audio-source";
interface MediaParticleViewProps {
particle: StreamParticle;
onEnded: () => void;
}
function formatTime(ms: number): string {
@@ -36,12 +35,12 @@ function DurationPill({
export function MediaParticleView({
particle,
onEnded,
}: MediaParticleViewProps) {
const cachedUrl = usePlaybackStore(
(s) => s.downloadUrlCache[particle.id],
);
const cacheDownloadUrl = usePlaybackStore((s) => s.cacheDownloadUrl);
const next = usePlaybackStore((s) => s.next);
const paused = usePlaybackStore((s) => s.paused);
const [error, setError] = useState<string | null>(null);
@@ -113,7 +112,7 @@ export function MediaParticleView({
crossOrigin="anonymous"
src={cachedUrl}
autoPlay
onEnded={onEnded}
onEnded={next}
onTimeUpdate={(e) => {
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
}}
@@ -134,7 +133,7 @@ export function MediaParticleView({
src={cachedUrl}
autoPlay
playsInline
onEnded={onEnded}
onEnded={next}
onTimeUpdate={(e) => {
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
}}
+18 -8
View File
@@ -10,15 +10,14 @@ import { AckButton } from "./ack-button";
interface ParticleRendererProps {
particle: StreamParticle;
onNext: () => void;
onPrev: () => void;
}
export function ParticleRenderer({
particle,
onNext,
onPrev,
}: ParticleRendererProps) {
const next = usePlaybackStore((s) => s.next);
const prev = usePlaybackStore((s) => s.prev);
const markParticlesSeen = useAppStore((s) => s.markParticlesSeen);
const markedRef = useRef<string | null>(null);
@@ -33,15 +32,15 @@ export function ParticleRenderer({
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
const rect = e.currentTarget.getBoundingClientRect();
const x = (e.clientX - rect.left) / rect.width;
if (x < 0.3) onPrev();
else if (x > 0.7) onNext();
if (x < 0.3) prev();
else if (x > 0.7) next();
};
const renderContent = () => {
switch (particle.type) {
case "media":
{/* NOTE: it's more robust to re-mount the MediaParticleView when the particle changes, to ensure playback state is well-behaved */}
return <MediaParticleView key={particle.id} particle={particle} onEnded={onNext} />;
{/* NOTE: it's more robust to re-mount the MediaParticleView when the particle changes, to ensure playback state is well-behaved */ }
return <MediaParticleView key={particle.id} particle={particle} />;
case "text":
return <TextParticleView particle={particle} />;
default:
@@ -61,3 +60,14 @@ export function ParticleRenderer({
</div>
);
}
function RenderParticle({ particle }: { particle: StreamParticle }) {
switch (particle.type) {
case "media":
return <MediaParticleView particle={particle} />;
case "text":
return <TextParticleView particle={particle} />;
default:
return <FallbackParticleView particle={particle} />;
}
}
+1 -5
View File
@@ -211,11 +211,7 @@ export function StreamPlayerPage() {
{/* Particle content — fills entire viewport */}
<div className="absolute inset-0">
{currentParticle && (
<ParticleRenderer
particle={currentParticle}
onNext={next}
onPrev={prev}
/>
<ParticleRenderer particle={currentParticle} />
)}
</div>