0

so I am trying to get my toastify to only show up once five minutes before the time I have specified. I tried using the useEffect hook, but the toast still shows up every minute or so. The output I used to track if it the date works, and it does show me that they are indeed different minutes, but it still does show up at least one other time after I clicked on close for the first toast.

Are there other options than the useEffect hook for this or how can I improve my code in general?

export default function App() {
  const [time, setTime] = useState(null);
  const [showToast, setShowToast] = useState(false);

  useEffect(() => {
    const targetTime = new Date(2022, 11, 20, 11, 7);
    const reminderTime = new Date(targetTime - 5 * 60000);
    const currentTime = new Date();

    const interval = setInterval(() => {
      console.log(currentTime.getMinutes() + " " + reminderTime.getMinutes());
      if (
        currentTime.getHours() === reminderTime.getHours() &&
        currentTime.getMinutes() === reminderTime.getMinutes()
      ) {
        notify();
      }
    }, 60000);

    setInterval(() => {
      setTime(new Date());
    }, 1000);

    return () => {
      clearInterval(interval);
    };
  }, []);

  const notify = () =>
    toast(customMsg, {
      icon: <InfoOutlinedIcon />,
      autoClose: false,
      closeOnClick: false
    });

  const customMsg = () => (
    <div>
      Hello Toaster Test
      <div>123</div>
    </div>
  );

  return (
    <div>
      <div> {time ? time.toString() : "Loading"}</div>
      <ToastContainer limit={1} />
    </div>
  );
}
FishyK
  • 121
  • 1
  • 7

2 Answers2

1

You are using setInterval which is generally used in case of recurring events. If you want to show notification only once then use setTimeout instead.

you can achieve the desired result by calculating the time diff between the current time and the time you want to show your toast and then using that time in setTimeout. This will set a timer in the background and notify function will be fired once the countdown reaches your desired time.

 useEffect(() => {
        const targetTime = new Date(2022, 11, 20, 11, 7-5);
        
 
        setTimeout(notify(), targetTime-Date.now());

      }, []);

targetTime - Date.now() will return time difference in ms and will not work if time difference is more than 2147483647ms.

best approach would be that you keep track of date and only set timeout on the target day or target hour. because setTimeout is asynchronous and will take resources for the time it is running in background.

0

You can try to remove all the notifications when display a new one .

export default function App() {
      const [time, setTime] = useState(null);
      const [showToast, setShowToast] = useState(false);
    
      useEffect(() => {
        const targetTime = new Date(2022, 11, 20, 11, 7);
        const reminderTime = new Date(targetTime - 5 * 60000);
        const currentTime = new Date();
    
        const interval = setInterval(() => {
          console.log(currentTime.getMinutes() + " " + reminderTime.getMinutes());
          if (
            currentTime.getHours() === reminderTime.getHours() &&
            currentTime.getMinutes() === reminderTime.getMinutes()
          ) {
            notify();
          }
        }, 60000);
    
        setInterval(() => {
          setTime(new Date());
        }, 1000);
    
        return () => {
          clearInterval(interval);
        };
      }, []);
    
      const notify = () => {
        toast.dismiss();
        toast(customMsg, {
          icon: <InfoOutlinedIcon />,
          autoClose: false,
          closeOnClick: false,
        });
    
        const customMsg = () => (
          <div>
            Hello Toaster Test
            <div>123</div>
          </div>
        );
    
        return (
          <div>
            <div> {time ? time.toString() : "Loading"}</div>
            <ToastContainer />
          </div>
        );
      };
    }
atum45 s
  • 115
  • 1
  • 6