Search code examples
javascriptreactjsnext.jsapi-designswr

SWR stuck in loading state. Even after request is completed


I am using SWR to complete a simple API request however after I just finished formatting the API how I wanted SWR is now stuck In it's loading state and I am very confused as to why I have tried a few different things and none have yet to resolve my issue.

I know the response from the API includes a JSON object and in the code I did try to convert to a JavaScript object however it seems to not help.

In the fetcher I have set it to return the data and dig into the JSON object, If I remove British_Roles from the return then Next.js will return an error saying the map is not a function.

Have a feeling it could be a simple issue I am missing, but please keep in mind I am no pro. Any help would be greatly accepted

import {
  Table,
  TableCaption,
  Thead,
  Tr,
  Th,
  Tbody,
  Td,
  Tfoot,
  Text,
  Accordion,
  AccordionItem,
  AccordionButton,
  AccordionPanel,
  AccordionIcon,
  Box,
  Center,
  Stack,
  Heading,
  VStack,
} from "@chakra-ui/react";
import useSWR from "swr";
import axios from "axios";
import ReactMarkdown from "react-markdown";
import remarkGfm from "remark-gfm";

const fetcher = async (url, key) => {
  const res = await axios.get(url, {
    headers: {
      Authorization: `Bearer ${key}`,
      "Content-Type": "application/json",
    },
  });
  return res.data.data.attributes;
};

export const InsurgentDropdown = () => {
  var key = process.env.REACT_APP_API_KEY;
  var key =
    "xxx";
  const { data, error } = useSWR(
    ["https://api.squadkitresearch.net/api/britishes/1?populate=%2A", key],
    fetcher
  );

  if (error)
    return console.log(error), (<div>Failed to load {error.message}</div>);
  if (!data) return <div>Loading...</div>;

// using roles or data in the map below makes no difference
  return (
    <>
        {data.map((faction) => (
          <VStack p="5">
            <Accordion allowToggle>
              <AccordionItem>
                <AccordionButton>
                  <Box flex="1" textAlign="left">
                    <Heading fontSize="20px">
                      {faction.role_name || "Data Error"}
                    </Heading>
                  </Box>
                  <AccordionIcon />
                </AccordionButton>
                <AccordionPanel>
                  Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed
                  do eiusmod tempor incididunt ut labore et dolore magna aliqua.
                  Ut enim ad minim veniam, quis nostrud exercitation ullamco
                  laboris nisi ut aliquip ex ea commodo consequat.
                </AccordionPanel>
              </AccordionItem>
            </Accordion>
            <Accordion allowToggle>
              <AccordionItem>
                <h2>
                  <AccordionButton>
                    <Box flex="1" textAlign="left">
                      <Heading fontSize="20px">
                        {faction.role_name || "Data Error"}
                      </Heading>
                    </Box>
                    <AccordionIcon />
                  </AccordionButton>
                </h2>
                <AccordionPanel pb={4}>
                  <Table variant="striped" colorScheme="teal">
                    <TableCaption fontSize="15px">
                      {faction.role_name || "Squad Kit Weapon Name"} Role
                      Information
                    </TableCaption>
                    <Thead>
                      <Tr>
                        <Th fontSize="20px">Primary Weapon</Th>
                        <Th fontSize="20px">Magazine Size</Th>
                        <Th fontSize="20px">Weapon Sights Type</Th>
                        <Th fontSize="20px">Weapon Firing Modes</Th>
                        <Th isNumeric fontSize="20px">
                          Magazine Count
                        </Th>
                      </Tr>
                    </Thead>
                    <Tbody>
                      <Tr>
                        <Td>{faction.Primary || "Data Error"}</Td>
                        <Td>
                          {faction.Primary_Magazine_Round_Amount ||
                            "Data Error"}
                        </Td>
                        <Td>{faction.Primary_Sights || "Data Error"}</Td>
                        <Td>{faction.Primary_Firing_Modes || "Data Error"}</Td>
                        <Td>
                          {faction.Primary_Magazine_Amount || "Data Error"}
                        </Td>
                      </Tr>
                    </Tbody>
                    <Tr>
                      <Th fontSize="20px">Secondary Weapon</Th>
                      <Th fontSize="20px">Magazine Size</Th>
                      <Th fontSize="20px">Weapon Sights Type</Th>
                      <Th fontSize="20px">Weapon Firing Modes</Th>
                      <Th isNumeric fontSize="20px">
                        Magazine Count
                      </Th>
                    </Tr>
                  </Table>
                </AccordionPanel>
              </AccordionItem>
            </Accordion>
          </VStack>
        ))}
    </>
  );
};

// API Response

{
    "data": {
        "id": 1,
        "attributes": {
            "Role_Name": "British Squad Lead (Iron Sights)",
            "createdAt": "2022-02-05T05:55:35.926Z",
            "updatedAt": "2022-02-05T05:55:38.194Z",
            "publishedAt": "2022-02-05T05:55:38.184Z",
            "locale": "en",
            "British_Roles": [
                {
                    "id": 1,
                    "role_name": "British Squad Lead (Iron Sights)",
                    "Primary": "L85A2 + Foregrip + Bipod",
                    "Primary_Sights": "Iron Sights",
                    "Primary_Firing_Modes": "Auto/Single",
                    "Primary_Magazine_Amount": 7,
                    "Primary_Magazine_Round_Amount": 30,
                    "Secondary": "L131A1",
                    "Secondary_Sights": "Iron Sights",
                    "Secondary_Firing_Modes": "Single",
                    "Secondary_Magazine_Amount": 2,
                    "Secondary_Magazine_Round_Amount": null,
                    "Secondary_Knife": "SA80 Bayonet"
                }
            ],
            "British_Role_Extras": [
                {
                    "id": 1,
                    "__component": "loadouts.third-slot",
                    "Third_Slot_Item": "L109A1 Fragmentation Grenade",
                    "Item_Amount": 2
                },
                {
                    "id": 1,
                    "__component": "loadouts.forth-slot",
                    "Forth_Slot_Item": "L132A1 White Smoke Grenade",
                    "Item_Amount": 2
                },
                {
                    "id": 2,
                    "__component": "loadouts.forth-slot",
                    "Forth_Slot_Item": "L152A1 Orange Smoke Grenade",
                    "Item_Amount": 1
                },
                {
                    "id": 3,
                    "__component": "loadouts.forth-slot",
                    "Forth_Slot_Item": "L152A1 Yellow Smoke Grenade",
                    "Item_Amount": 1
                },
                {
                    "id": 1,
                    "__component": "loadouts.fifth-slot",
                    "Fith_Slot_Item": "Field Dressing",
                    "Item_Amount": 2
                },
                {
                    "id": 1,
                    "__component": "loadouts.sixth-slot",
                    "Sixth_Slot_Item": "Field Binoculars",
                    "Item_Amount": 1
                },
                {
                    "id": 2,
                    "__component": "loadouts.sixth-slot",
                    "Sixth_Slot_Item": "Rally Point",
                    "Item_Amount": 1
                }
            ],
            "localizations": {
                "data": []
            }
        }
    },
    "meta": {}
}

Solution

  • You are missing attributes in object. Try changing

    return res.data.British_Roles;
    

    to

    return res.data.attributes.British_Roles;
    

    In future, always try to debug by adding a console.log before the return value, to ensure you are returning the correct values.

    const fetcher = async (url, key) => {
      const res = await axios.get(url, {
        headers: {
          Authorization: `Bearer ${key}`,
          "Content-Type": "application/json",
        },
      });
    
      //so you know the error occurs here due to missing 'attributes'
      console.log(res.data.attributes.British_Roles)
      return res.data.attributes.British_Roles;
    };
    

    const response = {
        "data": {
            "id": 1,
            "attributes": {
                "Role_Name": "British Squad Lead (Iron Sights)",
                "createdAt": "2022-02-05T05:55:35.926Z",
                "updatedAt": "2022-02-05T05:55:38.194Z",
                "publishedAt": "2022-02-05T05:55:38.184Z",
                "locale": "en",
                "British_Roles": [
                    {
                        "id": 1,
                        "role_name": "British Squad Lead (Iron Sights)",
                        "Primary": "L85A2 + Foregrip + Bipod",
                        "Primary_Sights": "Iron Sights",
                        "Primary_Firing_Modes": "Auto/Single",
                        "Primary_Magazine_Amount": 7,
                        "Primary_Magazine_Round_Amount": 30,
                        "Secondary": "L131A1",
                        "Secondary_Sights": "Iron Sights",
                        "Secondary_Firing_Modes": "Single",
                        "Secondary_Magazine_Amount": 2,
                        "Secondary_Magazine_Round_Amount": null,
                        "Secondary_Knife": "SA80 Bayonet"
                    }
                ],
                "British_Role_Extras": [
                    {
                        "id": 1,
                        "__component": "loadouts.third-slot",
                        "Third_Slot_Item": "L109A1 Fragmentation Grenade",
                        "Item_Amount": 2
                    },
                    {
                        "id": 1,
                        "__component": "loadouts.forth-slot",
                        "Forth_Slot_Item": "L132A1 White Smoke Grenade",
                        "Item_Amount": 2
                    },
                    {
                        "id": 2,
                        "__component": "loadouts.forth-slot",
                        "Forth_Slot_Item": "L152A1 Orange Smoke Grenade",
                        "Item_Amount": 1
                    },
                    {
                        "id": 3,
                        "__component": "loadouts.forth-slot",
                        "Forth_Slot_Item": "L152A1 Yellow Smoke Grenade",
                        "Item_Amount": 1
                    },
                    {
                        "id": 1,
                        "__component": "loadouts.fifth-slot",
                        "Fith_Slot_Item": "Field Dressing",
                        "Item_Amount": 2
                    },
                    {
                        "id": 1,
                        "__component": "loadouts.sixth-slot",
                        "Sixth_Slot_Item": "Field Binoculars",
                        "Item_Amount": 1
                    },
                    {
                        "id": 2,
                        "__component": "loadouts.sixth-slot",
                        "Sixth_Slot_Item": "Rally Point",
                        "Item_Amount": 1
                    }
                ],
                "localizations": {
                    "data": []
                }
            }
        },
        "meta": {}
    }
    
    console.log(response.data.attributes.British_Roles)