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:
@@ -8,7 +8,6 @@ import { useAudioSource } from "@/components/audio/use-audio-source";
|
|||||||
|
|
||||||
interface MediaParticleViewProps {
|
interface MediaParticleViewProps {
|
||||||
particle: StreamParticle;
|
particle: StreamParticle;
|
||||||
onEnded: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatTime(ms: number): string {
|
function formatTime(ms: number): string {
|
||||||
@@ -36,12 +35,12 @@ function DurationPill({
|
|||||||
|
|
||||||
export function MediaParticleView({
|
export function MediaParticleView({
|
||||||
particle,
|
particle,
|
||||||
onEnded,
|
|
||||||
}: MediaParticleViewProps) {
|
}: MediaParticleViewProps) {
|
||||||
const cachedUrl = usePlaybackStore(
|
const cachedUrl = usePlaybackStore(
|
||||||
(s) => s.downloadUrlCache[particle.id],
|
(s) => s.downloadUrlCache[particle.id],
|
||||||
);
|
);
|
||||||
const cacheDownloadUrl = usePlaybackStore((s) => s.cacheDownloadUrl);
|
const cacheDownloadUrl = usePlaybackStore((s) => s.cacheDownloadUrl);
|
||||||
|
const next = usePlaybackStore((s) => s.next);
|
||||||
const paused = usePlaybackStore((s) => s.paused);
|
const paused = usePlaybackStore((s) => s.paused);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
@@ -113,7 +112,7 @@ export function MediaParticleView({
|
|||||||
crossOrigin="anonymous"
|
crossOrigin="anonymous"
|
||||||
src={cachedUrl}
|
src={cachedUrl}
|
||||||
autoPlay
|
autoPlay
|
||||||
onEnded={onEnded}
|
onEnded={next}
|
||||||
onTimeUpdate={(e) => {
|
onTimeUpdate={(e) => {
|
||||||
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
|
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
|
||||||
}}
|
}}
|
||||||
@@ -134,7 +133,7 @@ export function MediaParticleView({
|
|||||||
src={cachedUrl}
|
src={cachedUrl}
|
||||||
autoPlay
|
autoPlay
|
||||||
playsInline
|
playsInline
|
||||||
onEnded={onEnded}
|
onEnded={next}
|
||||||
onTimeUpdate={(e) => {
|
onTimeUpdate={(e) => {
|
||||||
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
|
setCurrentTimeMs(e.currentTarget.currentTime * 1000);
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -10,15 +10,14 @@ import { AckButton } from "./ack-button";
|
|||||||
|
|
||||||
interface ParticleRendererProps {
|
interface ParticleRendererProps {
|
||||||
particle: StreamParticle;
|
particle: StreamParticle;
|
||||||
onNext: () => void;
|
|
||||||
onPrev: () => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ParticleRenderer({
|
export function ParticleRenderer({
|
||||||
particle,
|
particle,
|
||||||
onNext,
|
|
||||||
onPrev,
|
|
||||||
}: ParticleRendererProps) {
|
}: ParticleRendererProps) {
|
||||||
|
const next = usePlaybackStore((s) => s.next);
|
||||||
|
const prev = usePlaybackStore((s) => s.prev);
|
||||||
|
|
||||||
const markParticlesSeen = useAppStore((s) => s.markParticlesSeen);
|
const markParticlesSeen = useAppStore((s) => s.markParticlesSeen);
|
||||||
const markedRef = useRef<string | null>(null);
|
const markedRef = useRef<string | null>(null);
|
||||||
|
|
||||||
@@ -33,15 +32,15 @@ export function ParticleRenderer({
|
|||||||
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
const handleClick = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
const rect = e.currentTarget.getBoundingClientRect();
|
const rect = e.currentTarget.getBoundingClientRect();
|
||||||
const x = (e.clientX - rect.left) / rect.width;
|
const x = (e.clientX - rect.left) / rect.width;
|
||||||
if (x < 0.3) onPrev();
|
if (x < 0.3) prev();
|
||||||
else if (x > 0.7) onNext();
|
else if (x > 0.7) next();
|
||||||
};
|
};
|
||||||
|
|
||||||
const renderContent = () => {
|
const renderContent = () => {
|
||||||
switch (particle.type) {
|
switch (particle.type) {
|
||||||
case "media":
|
case "media":
|
||||||
{/* NOTE: it's more robust to re-mount the MediaParticleView when the particle changes, to ensure playback state is well-behaved */}
|
{/* 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} />;
|
return <MediaParticleView key={particle.id} particle={particle} />;
|
||||||
case "text":
|
case "text":
|
||||||
return <TextParticleView particle={particle} />;
|
return <TextParticleView particle={particle} />;
|
||||||
default:
|
default:
|
||||||
@@ -61,3 +60,14 @@ export function ParticleRenderer({
|
|||||||
</div>
|
</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} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -211,11 +211,7 @@ export function StreamPlayerPage() {
|
|||||||
{/* Particle content — fills entire viewport */}
|
{/* Particle content — fills entire viewport */}
|
||||||
<div className="absolute inset-0">
|
<div className="absolute inset-0">
|
||||||
{currentParticle && (
|
{currentParticle && (
|
||||||
<ParticleRenderer
|
<ParticleRenderer particle={currentParticle} />
|
||||||
particle={currentParticle}
|
|
||||||
onNext={next}
|
|
||||||
onPrev={prev}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user