From 70b723d5140cdcfa08019551966173804f81290e Mon Sep 17 00:00:00 2001 From: KevIsDev Date: Mon, 17 Feb 2025 01:49:33 +0000 Subject: [PATCH] fix: debounce profile update notifications to prevent toast spam a new toast was being triggered for every character input. --- .../@settings/tabs/profile/ProfileTab.tsx | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/app/components/@settings/tabs/profile/ProfileTab.tsx b/app/components/@settings/tabs/profile/ProfileTab.tsx index 6ea19fe4..21e917bd 100644 --- a/app/components/@settings/tabs/profile/ProfileTab.tsx +++ b/app/components/@settings/tabs/profile/ProfileTab.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react'; +import { useState, useCallback, useEffect } from 'react'; import { useStore } from '@nanostores/react'; import { classNames } from '~/utils/classNames'; import { profileStore, updateProfile } from '~/lib/stores/profile'; @@ -7,6 +7,32 @@ import { toast } from 'react-toastify'; export default function ProfileTab() { const profile = useStore(profileStore); const [isUploading, setIsUploading] = useState(false); + const [toastTimeout, setToastTimeout] = useState(null); + + const handleProfileUpdate = useCallback( + (field: 'username' | 'bio', value: string) => { + updateProfile({ [field]: value }); + + if (toastTimeout) { + clearTimeout(toastTimeout); + } + + const timeout = setTimeout(() => { + toast.success(`${field.charAt(0).toUpperCase() + field.slice(1)} updated`); + }, 1000); + + setToastTimeout(timeout); + }, + [toastTimeout], + ); + + useEffect(() => { + return () => { + if (toastTimeout) { + clearTimeout(toastTimeout); + } + }; + }, [toastTimeout]); const handleAvatarUpload = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; @@ -41,17 +67,6 @@ export default function ProfileTab() { } }; - const handleProfileUpdate = (field: 'username' | 'bio', value: string) => { - updateProfile({ [field]: value }); - - // Only show toast for completed typing (after 1 second of no typing) - const debounceToast = setTimeout(() => { - toast.success(`${field.charAt(0).toUpperCase() + field.slice(1)} updated`); - }, 1000); - - return () => clearTimeout(debounceToast); - }; - return (