Home > Blockchain >  Why's my code firing inconsistently using onDoubleClick to send the server data?
Why's my code firing inconsistently using onDoubleClick to send the server data?

Time:02-18

I cannot figure out for the life of me why the first pair of onDoubleClick fires 500 server error but on all subsequent onDoubleClicks, it fires 200 correctly but with inconsistent behavior depicted below.

For illustration purposes, this is what's happening:

  1. double click on image A for user ID 1 -> 500 error
  2. double click on image A for user ID 1 -> 200 success (updates successfully for user ID 1)
  3. double click on image B for user ID 2 -> 200 success (updates successfully for user ID 1 when it should've been updated for user ID 2)
  4. and so on....

I've checked all over SO, even tried all of the suggestions on the most popular question asked on this topic on SO but to no avail. I've hit a brick wall.

I believe it has something to do with the asynchronous nature of hooks and how I'm defining them but I'm not entirely sure.

How can I make it so that upon double clicking any image, the corresponding data gets sent to the server correctly on the first pair of double clicks as well as any subsequent pair double clicks (i.e. on a different image)?

For illustration purposes, this how I'd like it to behave:

  1. double click on image A for user ID 1 -> 200 success (updates successfully for user ID 1)
  2. double click* on image b for user ID 2 -> 200 success (updates successfully for user ID 2)
  3. and so on....
const Images = () => {
  let authToken = localStorage.getItem("token");

  const [uploadsData, setUploadsData] = useState([]);
  const [likedPhotoUserId, setLikedPhotoUsedId] = useState("");
  const [like, setLike] = useState(0);

  useEffect(() => {
    getUploads();
  }, []);

  useEffect(() => {}, [uploadsData]);

  const getUploads = () => {
    const headers = {
      Accept: "application/json",
      Authorization: `Bearer ${authToken}`,
    };

    axios
      .get("http://localhost:8005/api/get-user-uploads-data", { headers })
      .then((resp) => {
        console.log(resp.data);
        setUploadsData(resp.data);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  const handleLikesBasedOnUserId = (e) => {
    setLikedPhotoUsedId(e);
    sendUserLikePost();
  };

  const sendUserLikePost = () => {
    const url = "http://localhost:8005/api/post-user-like";

    const headers = {
      Accept: "application/json",
      Authorization: `Bearer ${authToken}`,
    };

    let data = {
      like: like,
      UserID: likedPhotoUserId,
    };

    console.log(data);

    axios
      .post(url, data, { headers })
      .then((resp) => {
        console.log(resp.data);
      })
      .catch((error) => {
        console.log(error);
      });
  };

  const displayUploadsData = () => {
    return uploadsData.map((photos, index) => {
      return (
        <ImagesGrid
          src={photos.url}
          likes={photos.likes}
          userName={photos.name}
          key={index}
          doubleClick={handleLikesBasedOnUserId}
          value={photos.UserID}
        />
      );
    });
  };

  return <>{displayUploadsData()}</>;
};

const ImagesGrid = (props) => {
  const createUserPhotoNodes = () => {
    return (
      <section className="gallery">
        <div className="container">
          <form method="POST" name="likes">
            <div className="img-container">
              <img
                src={props.src}
                alt="Photo"
                className="gallery-img"
                onDoubleClick={() => props.doubleClick(props.value)}
              />
              <h2 className="userName">{props.userName}</h2>
              <h2 className="likes" onChange={props.onChange}>
                Likes {props.likes}
              </h2>
            </div>
          </form>
        </div>
      </section>
    );
  };

  return <>{createUserPhotoNodes()}</>;
};

CodePudding user response:

You have hit the nail on the head – it's because setState is asynchronous and you're seeing stale props or state to boot.

With

const handleLikesBasedOnUserId = (e) => {
    setLikedPhotoUsedId(e);
    sendUserLikePost();
};

const sendUserLikePost = () => {
    // ...
    let data = {
        'like': like,
        'UserID': likedPhotoUserId
    };
    // ...

likedPhotoUserId will not have updated before you call sendUserLikePost, so likedPhotoUserId is ''. (By the time you call handleLikes... again it will have the "previous" value.)

I don't see a reason why likedPhotoUserId should be a state atom anyway, since all you use it for is sendUserLikePost – just make it a regular ol' parameter:

const handleLikesBasedOnUserId = (e) => {
    sendUserLikePost(e);
};

const sendUserLikePost = (likedPhotoUserId) => {
    // ...
    let data = {
        'like': like,
        'UserID': likedPhotoUserId
    };
    // ...
  • Related