I have one nestjs code and this is for create reaction and delete reaction alternative but when i click fast on this reaction button then it call same api 2 times example if i click on happy button fast then it call delete api two times, this is my nextjs code.
i tried with global variable and also try with settimeout. but it is not work. please give help me to solve this question.
import { REACTIONS } from '@/constants/index';
import GlobalContext, { GlobalContextType } from '@/contexts/global.context';
import requests from '@/utils/requests';
import Image from 'next/image';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import styles from './PostDetailReactions.module.css';
import { debounce } from 'lodash';
let processIsExecuted = 0;
const PostDetailReactions = ({ post }) => {
console.log(post);
const { handleRequireSignIn } = useContext<GlobalContextType>(GlobalContext);
const isSavingReaction = useRef(false);
const [reactionCount, setReactionCount] = useState({});
const [loading, setLoading] = useState(false);
const [reactions, setReactions] = useState([]);
const emojiMapping = {
love: '',
happy: '',
like: '',
wow: '',
annoyed: '',
mad: '',
};
useEffect(() => {
setReactionCount(
Object.values(REACTIONS).reduce((acc, reaction) => {
acc[reaction] = post[`${reaction}ReactionCount`];
return acc;
}, {}) || {},
);
setReactions(post?.reactions || []);
}, [post]);
const handleClickReaction = useCallback(
debounce(async (reaction) => {
console.log(reaction);
if (processIsExecuted == 0) {
processIsExecuted = 1;
// window.setTimeout(async () => {
if (!post) {
return;
}
if (isSavingReaction.current) {
return;
}
isSavingReaction.current = true;
console.log(reaction);
setLoading(true);
const alreadyReacted = reactions.some((item) => item.reaction === reaction);
if (alreadyReacted) {
try {
const updatedReactions = await requests.delete(`/api/v1/posts/${post.id}/reactions/${reaction}`);
setReactionCount({ ...reactionCount, [reaction]: Math.max(0, reactionCount[reaction] - 1) });
setReactions(updatedReactions);
console.log(reactions);
} catch (error) {
if (error.response && error.response.status === 404) {
console.error('Resource not found:', error.message);
} else {
console.error(error);
}
} finally {
console.log(loading);
setLoading(false);
console.log(loading);
isSavingReaction.current = false;
processIsExecuted = 0;
}
} else {
try {
const updatedReactions = await requests.post(`/api/v1/posts/${post.id}/reactions/${reaction}`);
console.log(updatedReactions, 'post');
setReactionCount({ ...reactionCount, [reaction]: reactionCount[reaction] + 1 });
setReactions(updatedReactions);
} catch (error) {
if (error.response && error.response.status === 404) {
console.error('Resource not found:', error.message);
} else {
console.error(error);
}
} finally {
setLoading(false);
isSavingReaction.current = false;
processIsExecuted = 0;
}
}
// }, 0);
}
}, 100),
[post, reactionCount, reactions],
);
return (
<div className={styles.reactions}>
{Object.entries(REACTIONS).map(([key, reaction]) => {
const isReacted = reactions.filter((item) => item.reaction === reaction).length;
return (
<button
key={`reaction_${key}`}
id={`reaction_${key}`}
disabled={loading}
className={`${styles.reaction} ${isReacted && styles.reacted}`}
onClick={() => handleRequireSignIn(() => handleClickReaction(reaction))}
>
<div className={styles.emoji}>
<span>{emojiMapping[reaction]}</span>
</div>
<div className={styles['reaction-count']}>
<span>{reactionCount[reaction]}</span>
</div>
</button>
);
})}
</div>
);
};
export default PostDetailReactions;