0

I am trying to fill a table with data from an API.

UPDATED*************

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

import {
  AppLayout,
  Button,
  Box,
  Form,
  SpaceBetween,
  Grid,
} from "@affn/awsui-components-react/polaris";
import "@affn/awsui-global-styles/polaris.css";
import "./styles/landing-page.scss";
import { appLayoutLabels, externalLinkProps } from "./common/labels";
import Picture1 from "./resources/engineLogos/bric_team_dark_backgroung(1).svg";
import {
  ExternalLinkItem,
  Navigation,
  InfoLink,
} from "./commons/common-components-BRIC";

function BricPage() {
  
  const Content = ({ navigationOpen }) => {
    //Constants needed by the form ------------------------------------------------
    
    const refreshPage = () => {
      window.location.reload();
    };

    // The comment (i.e conversation) id must be unique
    const conversationId = uuidv4();

    //Function to handle submit click and create SIM
    const handleClick = (
      title1,
      description1,
    ) => () => {
      console.log(title1);
      console.log(description1);

    };

    const [GetSimIDs, setGetSimIDs] = React.useState([]); //Which is the impacted region?

  // Using useEffect to call the API once mounted and set the data
  useEffect(() => {
    window.harxny.api
      .invokeProxy(
        "/sit/ises?sort=createDate desc&q=status:(Open) containingFolder:(45-b5b9-4829-8b87-489053f9bb42)",
        {
          method: "GET",
          // SIM integration is only possible from the 'beta' and 'corp' stages.
          stage: "corp",
          headers: {
            "Content-Type": "application/json",
          },
        }
      ) //api finishes here
      .then((xhr) => {
        //response is captured here
        //var SIMID = JSON.parse(xhr.response).id;
        console.log(xhr.responseText);
        const data = JSON.parse(xhr.response);
        //const data = xhr.response;
        console.log(data);
        console.log(data.totalNumberFound);
        setGetSimIDs(data);
        console.log(GetSimIDs);
      });
  }, []);


    //End of Constants -------------------------------------------------------------
    console.log(GetSimIDs);
    return (
      <Box margin={{ bottom: "l" }}>
      
        <div className="center-form">
          <Box>
            <Grid
              gridDefinition={[
                {
                  colspan: { xl: "2", l: "2", s: "5", xxs: "10" },
                  offset: { l: "2", xxs: "1" },
                },
                {
                  colspan: { xl: "2", l: "3", s: "5", xxs: "10" },
                  offset: { s: "0", xxs: "1" },
                },
              ]}
            >
              <div className="custom-home-main-content-area">
                <SpaceBetween size="l">
                  <Form
                    actions={
                      <SpaceBetween direction="horizontal" size="xs">
                        <Button onClick={refreshPage} variant="link">
                          Reset Form
                        </Button>

                        <Button
                          variant="primary"
                          onClick={handleClick(
                            title1,
                            description1,
                          )}
                          ariaLabel="Submit"
                        >
                          Submit
                        </Button>
                      </SpaceBetween>
                    }
                  >
                  </Form>
                </SpaceBetween>
              </div>

            {/* Table goes here */}

            {console.log(GetSimIDs)}


              <tbody>
                <tr>
                  <th>title</th>
                  <th>Id</th>
                </tr>
                {GetSimIDs.documents.map((item, i) => (
                  <tr key={i}>
                    <td>{item.title}</td>
                    <td>{item.id}</td>
                  </tr>
                ))}
              </tbody>
            </Grid>
          </Box>
        </div>
      </Box>
    );
  };

  const [navigationOpen, setNavigationOpen] = React.useState(false);

  return (
    <AppLayout
      disableContentPaddings={true}
      content={<Content />}
      navigation={<Navigation activeHref="#/" />}
      navigationOpen={navigationOpen}
      onNavigationChange={({ detail }) => setNavigationOpen(detail.open)}
      toolsHide={true}
      ariaLabels={appLayoutLabels}
    />
  );
}

export default BricPage;

The state GetSimIDs is updated successfully with data like this:

{
  "documents": [
    {
      "assignedFolder": "4a37-416c-8531-",
      "extensions": {
        "tt": {
          "impact": 5,
          "category": "EiC",
          "type": "IBug",
          "item": "Macro",
          "assignedGroup": "EiC",
          "justification": [],
          "minImpact": 5,
          "status": "Assd"
        }
      },
      "watchers": [
        { "id": "bric-primary@amazon.com", "type": "email" },
        { "id": "sssesuni@amazon.com", "type": "email" },
        { "id": "raaishwa@amazon.com", "type": "email" },
        { "id": "dipchakr@amazon.com", "type": "email" }
      ],
      "customFields": {
        "number": [{ "id": "fte_saving", "value": 0 }],
        "date": [
          { "id": "delivery_date", "value": "2022-05-17T15:43:49.825Z" }
        ],
        "string": [
          { "id": "category_of_the_request", "value": "Other" },
          { "id": "region_of_impact", "value": "NA" },
          { "id": "tool_type", "value": "Excel Macro" },
          {
            "id": "impacted_tool",
            "value": "Tickets Helper"
          }
        ]
      }
     
    },
    {
      "title": "Issue or Bug - Global Wizard - NA",
      "assignedFolder": "416c-8531-37fa3a701712",
      
      "watchers": [{ "id": "bprimary@a.com", "type": "email" }],
      "customFields": {
        "number": [{ "id": "fte_saving", "value": 0 }],
        "date": [
          { "id": "delivery_date", "value": "2022-05-13T02:22:46.751Z" }
        ],
        "string": [
          { "id": "category_of_the_request", "value": "Other" },
          { "id": "region_of_impact", "value": "NA" },
          { "id": "tool_type", "value": "Excel Macro" },
          { "id": "impacted_tool", "value": "Global Wizard" }
        ]
      }
      
    }
  ],
  "totalNumberFound": 2,
  "searchLogMessages": [],
  "startToken": ""
}

So I tried to update the table with the following code:

<tbody>
                <tr>
                  <th>title</th>
                  <th>Id</th>
                  <th>status</th>
                </tr>
                {GetSimIDs.map((documents, i) => (
                  <tr key={i}>
                    <td>{documents.title}</td>
                    <td>{documents.id}</td>
                    <td>{documents.status}</td>
                  </tr>
                ))}
              </tbody>

But I keep getting an error in line

{GetSimIDs.map((documents, i) => ( 

Saying that TypeError: s is undefined

Any idea as of why it seems not getting the data from the hook?

I am very new to react so all feedback would be appreciated.

Thanks Luis V.

luisvv93
  • 63
  • 1
  • 6
  • 1
    You are trying to set GetSimIDs with all your JSON object. Maybe set only the value you need sth like `data.documents`. Also note that your json file does not seem to contain any `id` or `status`. Are you sure `GetSimIDs` contain those values? And note that some entries in the json file do not contain `title` Maybe to check if a property exist or not. If you are using typescript you can use `documents?.title`. As a side suggestion I would not use `.map` if I am not changing the values inside the GetSimIDs. Instead I would use `forEach` – besjon_c May 23 '22 at 20:04
  • Due to NDAs I can not share the exact json sorry but yes it includes id and status. I tried data.documents and no luck :( I will try a forEach maybe because the error keeps saying that the line "GetSimIDs.documents.map((item, i) => ( " is undefiend ... – luisvv93 May 23 '22 at 20:18
  • 1
    Maybe a binding error? Try es6 function to bind to this? – Jeremy May 23 '22 at 20:33
  • 1
    `GetSimIDs` has an undefined initial state value, so trying to access into it on the initial render throws this error. See Brian Thompson's answer below. – Drew Reese May 23 '22 at 23:54
  • 1
    Maybe also you don't need to call it React.useState just useState([]) as you already import it – besjon_c May 24 '22 at 16:35

3 Answers3

4

This is a common problem with async data. The state is initially undefined, and is filled in later after the request has completed. There will always be at least one render before your data is loaded.

You can fix this in several ways, but the simplest would be to just initialize the state to an empty array:

const [GetSimIDs, setGetSimIDs] = React.useState([]);

Now the state is always defined, and you can map over it even before the data is loaded.

Another option would be to check the data before mapping it:

{GetSimIDs && GetSimIDs.map((documents, i) => (
Brian Thompson
  • 13,263
  • 4
  • 23
  • 43
2

Data returned from the API seems to be an object with a property documents which is an array. Either you can

setGetSimIDs(data.documents)

OR

GetSimIDs.documents.map(...)

Update (Codesandbox): Seems you're also missing a few null checks due to which there are errors. Initially the object + array are empty so we can't use the map function. Only when data has successfully loaded we can render the rows.

I have used your data set & made a mock api.

export default function App() {
  const [GetSimIDs, setGetSimIDs] = useState({});

  useEffect(() => {
    axios
      .get("https://getsimids.free.beeceptor.com/my/api/path")
      .then((res) => {
        setGetSimIDs(res.data);
      });
  }, []);
  return (
    <div className="App">
      <table>
        <tbody>
          <tr>
            <th>title</th>
            <th>Id</th>
            <th>status</th>
          </tr>
          {GetSimIDs.documents &&
            GetSimIDs.documents.length > 0 &&
            GetSimIDs.documents.map((documents, i) => (
              <tr key={i}>
                <td>{documents.title}</td>
                <td>{documents.id}</td>
                <td>{documents.status}</td>
              </tr>
            ))}
        </tbody>
      </table>
    </div>
  );
}
A G
  • 21,087
  • 11
  • 87
  • 112
  • I tried both but the same error persists :( – luisvv93 May 23 '22 at 20:18
  • @luisvv93 Pls see update. I've made a codesandbox which you can review. – A G May 23 '22 at 21:07
  • Thank you very much @Aseem Gautam i just replicated what you did and I am still not getting anything, but I think it is because I have included it in the wrong place, I am going to update the main questions so that you can see it – luisvv93 May 24 '22 at 16:06
  • I have updated the code in the question, I am not sure if I am usin the useEffect in the right place to be honest because when I print in the return() the array is blank – luisvv93 May 24 '22 at 16:17
1

First, you can log the value of GetSimIDs and GetSimIDs before the map function.

console.log(GetSimIDs, GetSimIDs.documents)
GetSimIDs.map...

It will probably be undefined as at the first load of the page it is not initialized.

I would suggest you set the const [GetSimIDs, setGetSimIDs] = React.useState([]); instead of empty.

For your further problem with react hooks (useEffect) I would suggest you setState outside the useEffect. Extract the method that fetches data e.g getData and then use it inside useEffect()

useEffect(()=>{getData()},[])
besjon_c
  • 170
  • 2
  • 12
  • You are right, for some reason it is not saving the info in the state const [GetSimIDs, setGetSimIDs] = React.useState([]); – luisvv93 May 24 '22 at 16:01
  • I have updated the code in the question, I am not sure if I am usin the useEffect in the right place to be honest because when I print in the return() the array is blank – luisvv93 May 24 '22 at 16:17
  • A quick fix would be to just check before the `map` {GetSimIDs && GetSimIDs.documents &$ GetSimIDs.map(... – besjon_c May 24 '22 at 16:17
  • 1
    @luisvv93 maybe put the `GetSimIDs` inside the useEffect at the end of the `use effect`. From `}, []);` to `}, [GetSimIDs]);` – besjon_c May 24 '22 at 16:21
  • It is working with that suggestion @besjon_c , thank you, now it keeps printing the info in the console , is that the right behavior? – luisvv93 May 24 '22 at 16:38
  • 1
    Yes because it is renderin multiple times and it is updating the GetSimIDs every time. I would suggest you extract your method that fetch data from `useEffect`. Create another function `getData`. So the `setState` would be outside of useEffect and then in useEffect just call that method only once. `useEffect(()=>{getData()},[])`. btw the reason why it renders multiple times it is here: https://stackoverflow.com/questions/53715465/can-i-set-state-inside-a-useeffect-hook. – besjon_c May 24 '22 at 16:43