0

I am trying to get the data using axios, and I built this code:

const getContactList = () => {
    var data = {
        "list_id": `${myListID}`,
    };
    const headers = {
        'Content-Type': 'application/json',
        'Authorization': process.env.apiKey,
    };
    axios({
        method: "POST",
        url: "http://localhost:3001/api/get-contacts",
        headers: headers,
        data: data,
    }).then(result => {
        const myRes = result.data.list_contacts;
        console.log(myRes);

        if (myRes != undefined && myRes.length > 0 && myRes != "None") {
            return (<div className="border rounded w-full p-2">
                <label>Data: </label>
                <select className="border rounded" name="mycontactlist" id="mycontactlist">
                    {myRes.map((item) => {
                        return (<option name={item.contact_name}>{item.contact_name}</option>)
                    })}
                </select>
            </div >)
        }

    }).
        catch(err => {
            return (<div>Could not get data.</div>)
        });
}

then I try to render it:

    return (<div>
    {getContactList()}
    </div>);

But unfortunately, I don't see anything. I also tried to return the whole axios but it didn't work.

When I log myRes, I see my array -

Array(4)
0: {contact_id: 1, contact_name: "contact", contact_number: "0505975250", contact_list_id: 1, list_id: 1, …}
1: {contact_id: 2, contact_name: "contact", contact_number: "0505975251", contact_list_id: 1, list_id: 1, …}
2: {contact_id: 3, contact_name: "contact", contact_number: "0505975252", contact_list_id: 1, list_id: 1, …}
3: {contact_id: 4, contact_name: "contact", contact_number: "0505972553", contact_list_id: 1, list_id: 1, …}
length: 4
__proto__: Array(0)

What did I do wrong?

I understand that it has something to do with the promise, but I don't get it. Can you help please?

Or Nakash
  • 1,345
  • 1
  • 9
  • 22
  • 1
    This exact type of question is asked several times a day on Stackoverflow. It's a duplicate of [How to return value from an asynchronous callback function?](https://stackoverflow.com/questions/6847697/how-to-return-value-from-an-asynchronous-callback-function) – Andy Ray Jun 19 '21 at 17:19
  • in the render, you should not put the function but a state value containing the result of the data you got from the response of the api call – VersifiXion Jun 19 '21 at 17:21
  • @AndyRay thank you for the response but I tried that and it didn't work - I want to be able to use the data inside the render function, not just return it to another function and I tried that and nothing :( – Or Nakash Jun 19 '21 at 17:22
  • @VersifiXion thank you, I tried that too but unfortunately, I am then stuck in an unlimited loop because everytime I get the data I change the state, and when I change the state I get the data over and over again... or am I wrong? – Or Nakash Jun 19 '21 at 17:23
  • You either need to put the response data into state and render your data based off state, or you need to move the fetch into a higher component, and not render your child component until the fetch finishes, and pass down the fetched data as props to the child component – Andy Ray Jun 19 '21 at 17:24
  • @AndyRay thanks again, Andy, can you show how to do it please? :) – Or Nakash Jun 19 '21 at 17:29

2 Answers2

1

You need to set the state when you get the data from the axios call. The state will determine how the component is rendered. Here is the code:

import { useState } from "react";
import * as axios from "axios";
import "./styles.css";

const url = "http://localhost:3001/api/get-contacts";

function Contacts(props) {
  const [selectOptions, setSelectOptions] = useState([]);
  const [isLoading, setIsLoading] = useState(false);
  const [error, setError] = useState("");

  const btnClickHandler = (e) => {
    const data = {
      list_id: `${props.myListID}`
    };
    const headers = {
      "Content-Type": "application/json",
      Authorization: process.env.apiKey
    };
    axios
      .post(url, data, {
        headers: headers
      })
      .then((result) => {
        const myRes = result.data.list_contacts;
        setSelectOptions(myRes);
        setIsLoading(false);
        setError("");
      })
      .catch((err) => {
        console.error(err);
        setSelectOptions([]);
        setIsLoading(false);
        setError("Could not get data.");
      });
    setIsLoading(true);
  };
  return (
    <div>
      {selectOptions !== undefined &&
        selectOptions.length > 0 &&
        selectOptions !== "None" && (
          <div className="border rounded w-full p-2">
            <label>Data: </label>
            <select
              className="border rounded"
              name="mycontactlist"
              id="mycontactlist"
            >
              {selectOptions.map((item) => {
                return (<option name={item.contact_name}>{item.contact_name}</option>)
              })}
            </select>
          </div>
        )}
      {isLoading && <p>Loading...</p>}
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button onClick={btnClickHandler} disabled={isLoading}>
        Get Contacts
      </button>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <Contacts myListID="1234" />
    </div>
  );
}
Rishabh Gupta
  • 734
  • 6
  • 10
0

As you are trying to do async rendering, you may have to go with Suspense.

https://reactjs.org/docs/concurrent-mode-suspense.html#what-is-suspense-exactly

https://codesandbox.io/s/frosty-hermann-bztrp

Anish Antony
  • 1,379
  • 8
  • 13