fix: memory leaks -- add setTimeout cleanup in ChatInput, SocialViewFeedItem, PostCard
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
d919f8c7c9
commit
9f7a42cdb5
3 changed files with 35 additions and 12 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { Card } from '../ui/card';
|
||||
import { Button } from '../ui/button';
|
||||
import { Badge } from '../ui/badge';
|
||||
|
|
@ -58,6 +58,15 @@ const PostCardComponent: React.FC<PostCardProps> = ({ post }) => {
|
|||
const [showComments, setShowComments] = useState(false);
|
||||
const [showShareModal, setShowShareModal] = useState(false);
|
||||
const [shareConfirmed, setShareConfirmed] = useState(false);
|
||||
const likeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const shareTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (likeTimeoutRef.current) clearTimeout(likeTimeoutRef.current);
|
||||
if (shareTimeoutRef.current) clearTimeout(shareTimeoutRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
// Mock comments
|
||||
const comments: Comment[] = post.recentComments || [
|
||||
|
|
@ -91,14 +100,16 @@ const PostCardComponent: React.FC<PostCardProps> = ({ post }) => {
|
|||
setLikesCount((prev) => (isLiked ? prev - 1 : prev + 1));
|
||||
if (!isLiked) {
|
||||
setLikeAnimating(true);
|
||||
setTimeout(() => setLikeAnimating(false), 400);
|
||||
if (likeTimeoutRef.current) clearTimeout(likeTimeoutRef.current);
|
||||
likeTimeoutRef.current = setTimeout(() => setLikeAnimating(false), 400);
|
||||
addToast('Liked post');
|
||||
}
|
||||
}, [isLiked, addToast]);
|
||||
|
||||
const handleShare = useCallback(() => {
|
||||
setShareConfirmed(true);
|
||||
setTimeout(() => setShareConfirmed(false), 1500);
|
||||
if (shareTimeoutRef.current) clearTimeout(shareTimeoutRef.current);
|
||||
shareTimeoutRef.current = setTimeout(() => setShareConfirmed(false), 1500);
|
||||
addToast('Shared!', 'success');
|
||||
}, [addToast]);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useCallback } from 'react';
|
||||
import React, { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { motion } from 'framer-motion';
|
||||
import { Card } from '@/components/ui/card';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
|
@ -16,19 +16,30 @@ export function SocialViewFeedItem({ track, onPlay }: SocialViewFeedItemProps) {
|
|||
const [likeCount, setLikeCount] = useState(track.like_count ?? 0);
|
||||
const [likeAnimating, setLikeAnimating] = useState(false);
|
||||
const [shareConfirmed, setShareConfirmed] = useState(false);
|
||||
const likeTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
const shareTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (likeTimeoutRef.current) clearTimeout(likeTimeoutRef.current);
|
||||
if (shareTimeoutRef.current) clearTimeout(shareTimeoutRef.current);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleLike = useCallback(() => {
|
||||
setIsLiked((prev) => !prev);
|
||||
setLikeCount((prev) => (isLiked ? prev - 1 : prev + 1));
|
||||
if (!isLiked) {
|
||||
setLikeAnimating(true);
|
||||
setTimeout(() => setLikeAnimating(false), 400);
|
||||
if (likeTimeoutRef.current) clearTimeout(likeTimeoutRef.current);
|
||||
likeTimeoutRef.current = setTimeout(() => setLikeAnimating(false), 400);
|
||||
}
|
||||
}, [isLiked]);
|
||||
|
||||
const handleShare = useCallback(() => {
|
||||
setShareConfirmed(true);
|
||||
setTimeout(() => setShareConfirmed(false), 1500);
|
||||
if (shareTimeoutRef.current) clearTimeout(shareTimeoutRef.current);
|
||||
shareTimeoutRef.current = setTimeout(() => setShareConfirmed(false), 1500);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
|
|
@ -61,12 +72,10 @@ export function SocialViewFeedItem({ track, onPlay }: SocialViewFeedItemProps) {
|
|||
</div>
|
||||
|
||||
<div className="px-4 pb-4">
|
||||
<div
|
||||
className="bg-card p-4 rounded-xl flex items-center gap-4 border border-border hover:border-primary/20 group cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
||||
<button
|
||||
type="button"
|
||||
className="appearance-none bg-transparent border-0 p-0 text-left w-full bg-card p-4 rounded-xl flex items-center gap-4 border border-border hover:border-primary/20 group cursor-pointer transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
||||
onClick={() => onPlay(track)}
|
||||
onKeyDown={(e) => e.key === 'Enter' && onPlay(track)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className="w-16 h-16 rounded-lg overflow-hidden relative">
|
||||
<img
|
||||
|
|
@ -87,7 +96,7 @@ export function SocialViewFeedItem({ track, onPlay }: SocialViewFeedItemProps) {
|
|||
<div className="text-xs text-muted-foreground font-mono pr-2">
|
||||
{track.duration}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="px-4 py-3 border-t border-border flex gap-2 text-xs text-muted-foreground">
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ export const ChatInput: React.FC = () => {
|
|||
} else {
|
||||
setTyping(false);
|
||||
}
|
||||
return () => {
|
||||
if (typingTimeoutRef.current) clearTimeout(typingTimeoutRef.current);
|
||||
};
|
||||
}, [message, setTyping]);
|
||||
|
||||
return (
|
||||
|
|
|
|||
Loading…
Reference in a new issue