Contradicted
Contradicted

Reputation: 21

How to display updated variable value without reloading page

I am attempting to get this function to run each time the value inside the 'for loop' changes, namely, the 'date' variable.

The purpose of the function below is to calculate the next upcoming prayer time. It looks at the list of prayer times held inside the object and then compares with one is the closest to the current time. Whichever one is the closest will be displayed and the process will repeat when the previous prayer time is no longer before the current time.

const [times, setTimes] = useState()
  const prayerData = timetable;
  let pinfo = {}

  function getNextPrayer() {

    for (const prayer in prayerData) {
      if (prayer.endsWith("_jammah")) {
        const jammahTime = dayjs(prayerData[prayer], 'hh:mm');
        if (dayjs().isBefore(jammahTime)) {
          setTimes(prayer)
          return {
            name: prayer,
            time: prayerData[prayer],
            remaining: jammahTime.toString()
          }
        }
      }
    }
  }

The object that holds the prayer time info:

const timetable = {
    "fajr_begins": "5:54",
    "fajr_jammah": "6:14",
    "zuhr_begins": "12:51",
    "zuhr_jammah": "13:30",
    "asr_begins": "15:28",
    "asr_jammah": "14:10",
    "maghrib_begins": "18:04",
    "maghrib_jammah": "19:49",
    "isha_begins": "19:27",
    "isha_jammah": "20:00"
}

I'm trying to get the page to re render every time the value of 'name' changes. Once one of the prayer time has passed the current time and its time for the next upcoming prayer, it will only display this next prayer when I reload the page. What I want is for this to become automatic so when it comes to the next prayer, it should refresh on its own and display the updated value. I've tried tracking the prayer name through state and using 'usestate' to update the value but it results in an infinite loop. Because I'm looping through the items in the 'timetable' object (which holds all the information of the prayer), if I try to update state here, it will result in an infinite loop.

EDIT: Currently, the time is 2:30pm so it displays 'asr_jammah' as the upcoming prayer. So when the prayer time exceeds the current time, it should move to the next prayer and display that as the next upcoming prayer without me having to reload the page for it to show which is what it currently does.

Screenshot of the application

How do I refactor this code so it is done automatically without causing an infinite loop?

Any help is greatly appreciated.

Upvotes: 0

Views: 39

Answers (1)

Bradley
Bradley

Reputation: 25

This will render the current prayer based on the time. Please provide more information on what exactly you are trying to render.

import React, { useEffect, useState } from "react";

type prayerDataType = {
  fajr_begins: string;
  fajr_jammah: string;
  zuhr_begins: string;
  zuhr_jammah: string;
  asr_begins: string;
  asr_jammah: string;
  maghrib_begins: string;
  maghrib_jammah: string;
  isha_begins: string;
  isha_jammah: string;
};

const prayerData = {
  fajr_begins: "5:54",
  fajr_jammah: "6:14",
  zuhr_begins: "12:51",
  zuhr_jammah: "13:30",
  asr_begins: "15:28",
  asr_jammah: "14:10",
  maghrib_begins: "18:04",
  maghrib_jammah: "19:49",
  isha_begins: "19:27",
  isha_jammah: "20:00",
};

const currentPrayer = () => {
  const [currentPrayer, setCurrentPrayer] = useState("");
  const [currentTime, setCurrentTime] = useState(new Date());

  function refreshClock() {
    setCurrentTime(new Date());
  }

  useEffect(() => {
    const timerId = setInterval(refreshClock, 1000);

    let currentAndPastPrayerDateTimes = [];
    for (const prayer in prayerData) {
      const prayerTime = prayerData[prayer as keyof prayerDataType];
      const [hours, minutes] = prayerTime.split(":");
      const prayerDateTime = new Date();
      prayerDateTime.setHours(parseInt(hours));
      prayerDateTime.setMinutes(parseInt(minutes));
      if (prayerDateTime <= currentTime) {
        currentAndPastPrayerDateTimes.push(prayerDateTime);
      }
    }

    const currentPrayerDateTime = new Date(
      Math.max(...currentAndPastPrayerDateTimes.map(Number))
    );
    const hours = currentPrayerDateTime.getHours();
    const minutes = currentPrayerDateTime.getMinutes();
    const currentPrayer = Object.keys(prayerData).find(
      (prayer) =>
        prayerData[prayer as keyof prayerDataType] === `${hours}:${minutes}`
    );

    setCurrentPrayer(currentPrayer ? currentPrayer : "");

    return function cleanup() {
      clearInterval(timerId);
    };
  }, []);

  return <div>{currentPrayer}</div>;
};

Upvotes: 2

Related Questions