Search code examples
javascriptreactjsasync-awaitfetchswr

SWR error, it's making multiple calls and data its ever undefined


Hi i'm trying to use SWR in my React app, but this generate an error because the data its ever undefined and when i check the network, i can se three calls to the api:

enter image description here

enter image description here

Table component:

import React, { , useEffect } from "react";
import {ProductService} from "../Services/product-service";
import { useDispatch, useSelector } from "react-redux";
import LinearProgress from "@mui/material/LinearProgress";
import useSWR from "swr";

function TableTransactions({ clientUserName, productNumber }) {
  const dispatch = useDispatch();
  const {data, isLoading, error} = useSWR(["transactions",clientUserName, productNumber,10], 
                                   ProductService.GetListTransactionsByParams(clientUserName, productNumber, 10));

  useEffect(()=>{
    (async()=>{
      //...;
  })();
 },[clientUserName, productNumber]);

 if(error) return <div>failed to load</div>
 if(isLoading) return <LinearProgress/>

return (
<>
  <Box>
    <TableContainer component={Paper}>
      <Table sx={{ minWidth: 650 }} size="small" aria-label="a dense table">
        <TableHead>
          <TableRow>
            <TableCell>
              <b>Tipo transacción</b>
            </TableCell>
            <TableCell >
              <b>Fecha</b>
            </TableCell>
            <TableCell >
              <b>Valor</b>
            </TableCell>
            <TableCell >
              <b>Producto origen</b>
            </TableCell>
            <TableCell >
              <b>Producto destino</b>
            </TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {data.map((row) => (
            <TableRow
              key={uuidv4()}
              sx={{ "&:last-child td, &:last-child th": { border: 0 } }}
            >
              <TableCell component="th" scope="row">
                {row.typeTransaction.name}
              </TableCell>
              <TableCell >{row.creationDate}</TableCell>
              <TableCell >{row.explicitValue}</TableCell>
              <TableCell >{row.originProductNumber}</TableCell>
              <TableCell >{row.destinyProductNumber}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </TableContainer>
  </Box>    
 </>
);
}
export default TableTransactions;

My function caller fetcher:

async function GetListTransactionsByParams(userName, productNumber, maxCount=10){
 try{
    var objSearch = {clientUserName: userName, productNumber: productNumber, maxCount:maxCount};
    
    let route = ClientSettings.UrlBaseInfoBankApi+"ProductInfo/ListTransactionsClient";
    let bearer = null;

    var response = await fetch(route,{
        method: "POST",
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + bearer,
        },
        //credentials: "include",
        body: JSON.stringify(objSearch)
    });

    await HandleResponseService(response);

    let json = await response.clone().json();
    if (response.status == 200 && json.response === true && json.error === "") {
        return json.data;
    }

    return null;
 }catch(err){
    throw new Error("Error connecting or timeout service: "+err);
    return null;
 }
}

I try to check {data ? && data.mapa(...)} but this only fix the console error, and data continues ever being undefined.


Solution

  • I had to change the way to return data from my fetcher function:

    const GetListTransactionsByParams= async(userName, productNumber, maxCount=10, fromDate, untilDate)=>{
     try{
        //...
        
        let route = ClientSettings.UrlBaseInfoBankApi+"ProductInfo/ListTransactionsClient";
        let bearer = null;
    
        var response = await fetch(route,{
            method: "POST",
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json',
                'Authorization': 'Bearer ' + bearer,
            },
            //credentials: "include",
            body: JSON.stringify(objSearch)
        });
    
        await HandleResponseServiceFetch(response);
        
        const data = await response.clone().json();
        return data.data;
     }catch(err){
        throw new Error("An error occurred while fetching the data: "+err);
     }
    }
    

    And i had to change the way to generate a key for swr, apply adittional configuration for avoid automatic re-fetch and use ()=> for apply direct cll to fetcher:

    function generateKey(clientUserName, productNumber, maxCount) {
      return `${clientUserName}-${productNumber}-${maxCount}`;
    }
    
    const key = generateKey(clientUserName, productNumber, maxCount);
    
    const {
     data = [],
     isLoading,
     isValidating,
     error,
     mutate} = useSWR([key],() => ProductService.GetListTransactionsByParams(
        clientUserName,
        productNumber,
        maxCount,
        dateFrom,
        dateUntil
      ),
     {
       revalidateOnFocus: false, 
       revalidateOnReconnect: false, 
     });