React, using "useFetch" is not working when parameter is passed

32 Views Asked by At

I was using a basic useFecth for a GET request from my JSON server file. I was working well. But later I wanted add extra functionality and make it work for POST and for another API too. The thing its still working with my json file, but doesnt work with the API. (btw the API is using FormData, thats why im sending as FormData. But when I run calendar page it seems like "useFetch" in there is not even running)

This is my App.js:

import './App.css';
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom';
import Home from './Pages/Home';
import About from './Pages/About';
import NavBottom from './Components/NavBottom';
import NavTop from './Components/NavTop';
import useFetch from './Components/useFetch';
import Admission from './Pages/Admission';
import Calendar from './Pages/Calendar';

function App() {
  const {data: user, error, isPending} = useFetch('http://localhost:8000/users/1');
  const {data: apiData, error: apiError, isPending: apiIsPending} = useFetch('http://localhost:8000/apiData/1');


  return (
    <div className="App">
      {error && <div>{error}</div>}
      {isPending && <div>Loading...</div>}
      {user && (
        <div>
          <Router>
            <nav>
                <NavTop user={user} />
                <NavBottom />
            </nav>

            <div className="content">
              <Routes>
                <Route path="/" element={<Home user={user}/>} />
                <Route path="/calendar" element={<Calendar user={user} apiData={apiData}/>} />
                <Route path="/about" element={<About />} />
                <Route path="/admission" element={<Admission />} />
              </Routes>
            </div>
          </Router>
        </div>
      )}
    </div>
  );
}

export default App;

This is the calendar page Calendar.js

import React from 'react'
import useFetch from '../Components/CalendarFetch'
import { useState } from 'react';

const Calendar =  ({user, apiData}) => {

    const apiFormData = new FormData();
    apiFormData.append('school_group', apiData.schoolGroup);
    apiFormData.append('db', apiData.db);
    apiFormData.append('student_idx', user.calendarId);

    
    const {data: calendar, error: calError, isPending: calIsPending} = useFetch('https://MY-API-LINK', apiFormData);

  return (
    <div>
        {calError && <div>{calError}</div>}
        {calIsPending && <div>Loading...</div>}
        {calendar && 
        
        <div>
            <h2>Calendar</h2>
            {console.log(calendar)}
        </div>
        }
    </div>
  )
}

export default Calendar

and this is my useFetch.js

import { useState, useEffect } from 'react';

const useFetch = (url, formData = null) => {
    const [data, setData] = useState(null);
    const [isPending, setIsPending] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        console.log(url)

        const abortCont = new AbortController();

        const fetchData = async () => {
            try {
                const fetchOptions = {
                    method: 'GET',
                    signal: abortCont.signal,
                };


                if (formData) {
                    fetchOptions.method = 'POST';
                    fetchOptions.body = formData;
                }

                const response = await fetch(url, fetchOptions);

                if (!response.ok) {
                    throw Error('Could not fetch the data for that resource!');
                }

                const responseData = await response.json();
                setData(responseData);
                setIsPending(false);
                setError(null);
            } catch (err) {
                if (err.name === 'AbortError') {
                    console.log('Fetch aborted');
                } else {
                    setIsPending(false);
                    setError(err.message);
                }
            }
        };

        fetchData();

        return () => abortCont.abort();
    }, [url, formData]);

    return { data, isPending, error };
};

export default useFetch;

I tried to to just pass it into the useFetch in calendar. but it returns fetch aborted

1

There are 1 best solutions below

0
On

It’s because you’re aborting the fetch every time the formData object referentially changes and you’re creating a new FormData object on each render

Wrapping your form data object in useMemo would solve your problem