0

So, I found similar issues that were not quite the same and didn't help me understand my problem.

I'm building a simple task manager using React and Firebase. I'm fetching data using a custom hook, since different components need to fetch data from Firebase. When the page loads, I get an infinite loop inside the custom hook, that's my issue.

Here's the component that triggers the custom hook:

const AllTasks = () => {
  const [tasks, setTasks] = useState([]);

  const renderTasks = (taskObj) => {
    const loadedTasks = [];

    for (const key in taskObj) {
      loadedTasks.unshift({
        id: key,
        date: taskObj[key].Date,
        client: taskObj[key].Client,
        task: taskObj[key].Task,
        time: taskObj[key].Time,
      });
    }
    setTasks(loadedTasks);
  };

  const { sendRequest: retrieveTasks } = useHttp();

  const refresh = retrieveTasks(
    {
      url: "https://myurl.com/alltasks.json",
    },
    renderTasks
  );

  // Loads tasks
  // useEffect(() => {
  //   retrieveTasks(
  //     {
  //       url: "https://myurl.com/alltasks.json",
  //     },
  //     renderTasks
  //   );
  // }, []);

  // Takes input value from task form and sends it to Firebase

  const enteredDateRef = useRef();
  const enteredClientRef = useRef();
  const enteredTaskRef = useRef();
  const enteredTimeRef = useRef();

  const renderNewTask = (data) => {
    const taskData = {
      id: data.name,
      date: data.Date,
      client: data.Client,
      task: data.Task,
      time: data.Time,
    };

    setTasks((tasks) => [taskData, ...tasks]);
  };

  const { sendRequest: postTask } = useHttp();

  const submitTaskHandler = async (event) => {
    event.preventDefault();

    const enteredDate = enteredDateRef.current.value;
    const enteredClient = enteredClientRef.current.value;
    const enteredTask = enteredTaskRef.current.value;
    const enteredTime = enteredTimeRef.current.value;

    const newTaskData = {
      Date: enteredDate,
      Client: enteredClient,
      Task: enteredTask,
      Time: enteredTime,
    };

    postTask(
      {
        url: "https://myurl.com/alltasks.json",
        method: "POST",
        body: newTaskData,
        headers: { "Content-Type": "application.json" },
      },
      renderNewTask
    );
  };

  return (
    <Fragment>
      <TasksHeader />

      <section className="w-full mt-4">
        <CardDark backgroundType="liquid">
          <h2>This month alone</h2>
          <div className="flex mt-4 justify-between">
            <div>
              <p className=" text-6xl font-medium">56.4</p>
              <p className="mt-2">Hours input</p>
            </div>
            <div className="border border-white"></div>
            <div>
              <p className=" text-6xl font-medium">1,378.45 €</p>
              <p className="mt-2">Cash generated</p>
            </div>
            <div className="border border-white"></div>
            <div>
              <p className=" text-6xl font-medium">128</p>
              <p className="mt-2">Tasks input</p>
            </div>
          </div>
        </CardDark>
      </section>

      <section>
        <SearchBar />
        <div className="flex justify-between mt-4">
          <h2>Your tasks</h2>
          <div className="flex">
            <h2 className="mr-2">Filters:</h2>
            <form className="text-gray-400" action="">
              <input type="date" className=" bg-gray-50 w-[120px] mr-2" />
              <input type="date" className=" bg-gray-50 w-[120px] mr-2" />
              <select id="cars" name="cars" className="bg-gray-50">
                <option value="volvo">Volvo</option>
                <option value="saab">Saab</option>
                <option value="fiat">Fiat</option>
                <option value="audi">Audi</option>
              </select>
            </form>
          </div>
        </div>
      </section>

      <section>
        <CardWhite>
          <form
            action=""
            onSubmit={submitTaskHandler}
            className="h-[50px] flex"
          >
            <input
              ref={enteredDateRef}
              type="date"
              className="h-[50px] focus:outline-none w-1/5 rounded-l-2xl border border-gray-300 px-4"
            />
            <input
              ref={enteredClientRef}
              type="text"
              className="h-[50px] focus:outline-none w-1/5 border-y border-gray-300 px-4"
              placeholder="Client name"
            />
            <input
              ref={enteredTaskRef}
              type="text"
              className="h-[50px] focus:outline-none grow border-y border-l border-gray-300 px-4"
              placeholder="Task"
            />
            <div className="h-[50px] flex w-1/10 rounded-r-2xl border border-gray-300 pl-4">
              <input
                ref={enteredTimeRef}
                type="time"
                className="focus:outline-none h-full"
              />
              <button type="submit" className="h-full p-2">
                <img src={SubmitIcon} className="h-full" alt="" />
              </button>
            </div>
          </form>
          <List
            tasks={tasks}
            refresh={refresh}
          />
        </CardWhite>
      </section>
    </Fragment>
  );
};

export default AllTasks;

and here's the custom hook:

const useHttp = () => {
    
    const sendRequest = async (requestConfig, applyData) => {

    const response = await fetch(requestConfig.url, {
      method: requestConfig.method ? requestConfig.method : "GET",
      body: requestConfig.body ? JSON.stringify(requestConfig.body) : null,
      headers: requestConfig.headers ? requestConfig.headers : {},
    });

    const responseData = await response.json();

    applyData(responseData);

    console.log('request');
  };
  return { sendRequest };
};

export default useHttp;

I'm guessing it has something to do with the way the custom hook is called inside the component, but I'm completely lost. I don't even know what triggers it in the first place. Can anyone help me? My goal is to trigger it once, when the page loads and when I submit a new task with the form.

I put the whole code since I don't really where the problems are.

Thanks in advance.

  • _"I'm guessing..."_: what steps have you taken to debug this code? Adding breakpoints, logging the results, checking the dev tools console log, network tabs? Anything? – Andy Aug 16 '22 at 13:02
  • I think the main problem is that the first file creates a function called renderTasks which changes the state of the component. It is then called by the useHttp hook. When the state change occurs, the component re-renders. This causes useHttp to call it again and so on and so forth. – Aaditey Nair Aug 16 '22 at 13:06
  • @Andy yes, after adding the breakpoints I noticed the code just get "stuck" inside the useHttp hook and never leaves. console.log('request') logs over and over and never stops. I did not check the network tab, will do that. – Lucas Vidal Aug 17 '22 at 10:55
  • @AaditeyNair I see what you mean. What I don't get is what triggers it in the first place (on page load), since I'm not using useEffect or anything like that. I'm guessing I did something wrong when destructuring and aliasing the custom hook here: `const { sendRequest: retrieveTasks } = useHttp();` – Lucas Vidal Aug 17 '22 at 10:59
  • @LucasVidal you call retrieveTasks to return data to the constant refresh. retrieveTasks calls the renderTasks. renderTasks re-renders the component which, to get the value of refresh, calls retrieveTasks again. – Aaditey Nair Aug 19 '22 at 11:24

0 Answers0