skip to Main Content

I used while loop for polling the API response, inside a modal.

The problem is that this while loop is not being aborted even when the modal is closed.

Please check the codesandbox to see actual code running.

In the sandbox above, you’ll see the console.log keeps running even when you close the modal.

I expected that the while loop will be aborted since the modal is being conditionally rendered, and it should be unmounted if it’s not being rendered.

can anyone explain why the while loop is alive?

import React from "react";
import "./styles.css";

const Modal = () => {
  const wait = async (ms = 1000) => {
    return new Promise((resolve) => setTimeout(resolve, ms));
  };

  let count = 0;
  const pollIncrement = async () => {
    while (count < 100) {
      await wait(2000);
      console.log(++count);
    }
    return count;
  };

  React.useEffect(() => {
    pollIncrement();
  }, []);

  return (
    <div
      style={{
        background: "blue",
        color: "white",
        width: "400px",
        height: "400px"
      }}
    >
      {count}
    </div>
  );
};

export default function App() {
  const [isModalOpen, setIsModalOpen] = React.useState(false);

  return (
    <>
      <button onClick={() => setIsModalOpen(!isModalOpen)}>open modal</button>
      {isModalOpen && <Modal />}
    </>
  );
}

3

Answers


  1. Your useEffect may optionally return a cleanup function.
    When you unmount the Modal, React does not automatically terminate the executing code for you. You need to handle this issue manually.

    const Modal = () => {
      const wait = async (ms = 1000) => {
        return new Promise((resolve) => setTimeout(resolve, ms));
      };
    
      let count = 0;
      const mounted = React.useRef(false)
      const pollIncrement = async () => {
        while (count < 100 && mounted.current) {
          await wait(2000);
          console.log(++count);
        }
        return count;
      };
    
      React.useEffect(() => {
        mounted.curren t= true
        pollIncrement();
        return ()=>{mounted.current = false}
      }, []);
    
      return (
        <div
          style={{
            background: "blue",
            color: "white",
            width: "400px",
            height: "400px"
          }}
        >
          {count}
        </div>
      );
    };
    Login or Signup to reply.
  2. To come out of the while loop, you try to use endloop; if it doesn’t work, if name is empty, other statements will not execute, and the entire loop will shut down.

    Login or Signup to reply.
  3. You can consider setInterval as it might be more suited for you are trying to achieve.

    const intervalId = useRef();
    
    useEffect(() => {
      // doWork is function containing logic you want executed every 2 seconds
      intervalId.current = setInterval(doWork, 2000);
    
      return () => { 
        clearInterval(intervalId.current); 
      }
    }, [])
    

    Function you return from the useEffect will be executed when component unmounts, making it convenient for cleanup work, such as stopping/canceling running jobs.

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