1

I'm making a react app that works with a API that provides data to my App. In my data base I have data about pins on a map. I want to show the info of those pins on my react app, I want them to render. I get that information with axios and this url: http://warm-hamlet-63390.herokuapp.com/pin/list I want to retrieve the info from that url, with axios.get(url), stringify the JSON data and then parse it to an array of pins.

The Problem: My page will be rendered before I get the data back from the server, because axios is async, so I will not be able to show anything. UseEffect and useState won't work because I need something in the first place (I think).

What i've tried: I tried to use useEffect and useState, but as I said, I think I need something in the first place to change it after. I also tried to use await, but await won't stop the whole React App until it has a response, although it would be nice if there is something that stops the app and waits until I have the array with the info so I can show it on the App then. I tried everything with async. I'm fairly new to React so there might be something basic i'm mssing (?). I've been on this for days, I can't get this to work by any means.. Any help, youtube videos, documentation, examples, is help. Anything. How the hell do I render something that needs to wait for the server respond?

My code:

//function that stores the data in the result array, 
//but result array will only be available after the 
//server response, and after the page is rendered
async function pin(){

  const result = []
  var url = "http://warm-hamlet-63390.herokuapp.com/pin/list"

  const res = await axios.get(url)
  
  console.log(res.data.data);

  if(res.data){
    const txt = JSON.stringify(res.data.data)
    const result = JSON.parse(txt)
    console.log(result);
  }
  return result;
}
class App extends React.Component{

  render(){
    return(
      <div>
        <Pin/>
        <Mapa/>
      </div>
    )
  }
}


export default App
4
  • Are you trying to render a component or data? Commented Jun 12, 2021 at 14:24
  • Any solution would work, because I want to use the said data on a component, does that make sense? Commented Jun 12, 2021 at 14:25
  • 1
    Can't you write the result to this.someVar = result; And then chceck it in template with if(someVar)? Commented Jun 12, 2021 at 14:27
  • So, which answer helped you? You should mark it as correct for the person who took time to help you and potential future viewers. It’s part of the what makes this site great. Commented Jun 12, 2021 at 22:49

2 Answers 2

4

I don't fully understand what you are trying to output but how you would usually handle this is with both the useState hook and the useEffect hook see example below.

  //function that stores the data in the result array, 
  //but result array will only be available after the 
  //server response, and after the page is rendered
  const pin = () => {
  const [result, setResults] = useState([]);
  var url = "http://warm-hamlet-63390.herokuapp.com/pin/list"

  useEffect(() => {
    //Attempt to retreive data
    try {
      const res = transformData();

      if (res) {
        // Add any data transformation
        setResults(transformData(res))
      }
      else {
        throw (error)
      }
    }
    catch (error) {
      //Handle error
    }
  }, [])

  // Handle data transformation
  const transformData = async () => {
    const res = await axios.get(url)

    const txt = JSON.stringify(res.data.data)
    const result = JSON.parse(txt)

    return result
  }

  if (!result) {
    // Return something until the data is loaded (usually a loader)
    return null
  }

  // Return whatever you would like to return after response succeeded
  return <></>;
}

This is all assuming that Pin is a component like you have shown in your code, alternatively, the call can be moved up to the parent component and you can add an inline check like below to render the pin and pass some data to it.

{result && <Pin property={someData} />}

Just a bit of background the useEffect hook has an empty dependency array shown at the end "[]" this means it will only run once, then once the data has updated the state this will cause a rerender and the change should be visible in your component

Sign up to request clarification or add additional context in comments.

6 Comments

thanks for trying to help me. I get this error: Unexpected reserved word 'await' maybe because there is no "async" in the code you posted, but I don't know where to put it either
Can't use await without declaring the containing function as async
Yes sorry, I forgot about that I have updated the code above and also moved the axios to the function as React doesn't like you using async in useEffect hook.
Otherwise you could just add the async like this useEffect(async () => {}
@VukVucic that actually doesn't work. But there's ways around it, see stackoverflow.com/a/56838577/9830755 or my answer.
|
1

Rest assured, useEffect() will work. You need to use a condition to conditionally render the content when it comes back from the server.

In the example below if results has a length < 1 the message Loading ... will be rendered in the containing <div>, once you're results are received the state will be updated (triggering a re-render) and the condition in the template will be evaluated again. This time though results will have a length > 1 so results will be rendered instead of Loading ...

I’m operating under the assumption that you’re function pin() is returning the results array.

const app = (props) => {
    
  const [results, setResult] = useState([]);
    
  React.useEffect(() => {
    const getPin = async () => {
      if (!results) {
        const results = await pin();
        setResult([…results])
      }
    }
    getPin();
  },[results]);
    
  return (
    <div>
      {result.length ? result : 'Loading ... '}
    </div>
  )
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.