skip to Main Content

I have a page with a Button A. When clicked, it makes an API call, and if successful, opens a new page. While the API call is being made, a modal appears to inform the user that a request is ongoing.

The modal contains a cancel button. If clicked, the new page should not open, and the state should reset so the user can cancel again if needed.

I use the useEffect hook to detect if the cancel button is clicked. If it is, the new page will not open. For the api call, I used await instead of settimeout(..)

I need to reset the variables in useEffect after the new page is either opened or not. I haven’t found a solution that handles the asynchronous nature of JavaScript. It’s essential to ensure that every time the cancel button is clicked, the user can click Button A and cancel the action repeatedly.

import React, {  useState, useRef, useEffect  } from 'react';

export default function NewApp(props) {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [apiRequestSuccessful, setApiRequestSuccessful] = useState(false);
  const [isCancelClicked, setIsCancelClicked] = useState(false);


  const handleButtonClick = async () => {
    // Open the modal
    setIsModalOpen(true);
    setIsCancelClicked(false);

    try {
      // Make the API request
      setTimeout(()=>{
        console.log("making api call")
      },3000)
        setApiRequestSuccessful(true);
    } catch (error) {
      console.error('API request failed', error);
    }
  };

  const handleCancelClick = () => {
    setIsCancelClicked(true);
    setIsModalOpen(false);
  };

  useEffect(() => {
    // Check if the API request was successful and the cancel button wasn't clicked
    if (apiRequestSuccessful && !isCancelClicked) {
     window.open('https://example.com', '_blank');
    // console.log("open new window")
    }
    setIsModalOpen(false)
  }, [apiRequestSuccessful, isCancelClicked]);

  return (
    <div>
      <button onClick={handleButtonClick}>Button A</button>
      {isModalOpen && (
        <Modal onCancel={handleCancelClick} />
      )}
    </div>
  );
};

const Modal = ({ onCancel }) => {
  return (
    <div className="modal">
      <p>Api call is being made...</p>
      <button onClick={onCancel}>Cancel</button>
    </div>
  );
};

2

Answers


  1. Why not store the fetch object in the state and once the cancel button is clicked you can cancel the fetch request? In the effect you can monitor the state of your fetch, if the fetch is canceled it will not open the new page but if it’s successful it will close the modal and present the new page. By that, there is no need to disable the cancel button; all states will be connected to your API request status.
    But if you insist on using state, can you explain when the state needs to be reseated and what state needs to be rested?

    Login or Signup to reply.
  2. Cancelling promises is difficult, you can store the request state in a state variable but you also have to store the request number or ID so that only the last request will count to go to the next page.

    const [requestNum, setRequestNum] = useState(0);
    const [showModal, setShowModal] = useState(false);
    
    handleCancelClick = () => {
      this.setRequestNum(this.requestNum + 1)
      this.setShowModal(false)
    }
    
    handleShowModalClick = () => {
      const reqNum = this.requestNum
      this.setShowModal(true)
      try {
        // Make the API request
        setTimeout(() => {
           // API request success opens new page
           if (reqNum === this.requestNum) {
             window.open('https://example.com', '_blank');
           }
        },3000)
      } catch (error) {
        console.error('API request failed', error);
      }
    }
    

    In this simplified example, the page only changes if the request is the latest request made, you can apply the same logic and if the request fails and is the latest request show an error message on the modal (if its open) etc.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search