Instead calling api post and delete api alternative if i click on button fast then it call 2 time same api

23 Views Asked by At

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;

0

There are 0 best solutions below