Home > Software design >  Javascript, then method not waiting for async function in React
Javascript, then method not waiting for async function in React

Time:03-07

I'm trying to set the background of my React App to the NASA APOD (Astronomy Picture of the Day). Here is my code for that:

import './App.css';
import React, { useState, useEffect } from "react";

const apiKey = process.env.REACT_APP_NASA_KEY;

function App() {
  const [bg, setBg] = useState(null);

  async function fetchPhoto() {
    const dat = await fetch(`https://api.nasa.gov/planetary/apod?api_key=${apiKey}`);
    const data = await dat.json();
    setBg(data); 
  }

  useEffect(() => {
    fetchPhoto().then(() => {
      document.body.style.backgroundImage = `url('${bg.url}')`
    })
  }, [])

  return null;
}

However, in this code then does not wait for the state to be set and I get the error:

App.js:22 Uncaught (in promise) TypeError: Cannot read properties of null (reading 'url')at App.js:22:1

What am I doing wrong? Thanks!

CodePudding user response:

1. Solution

A simpler way to achieve what you want is by doing like below, this way you don't have to menage asynchronous tasks like you are doing:

import './App.css';
import React, { useState, useEffect } from "react";

const apiKey = process.env.REACT_APP_NASA_KEY;

function App() {
  const [bg, setBg] = useState(null);

  async function fetchPhoto() {
    const dat = await fetch(`https://api.nasa.gov/planetary/apod?api_key=${apiKey}`);
    const data = await dat.json();
    setBg(data); 
  }
  
  useEffect(() => {
    fetchPhoto()
  }, [])

  useEffect(() => {
    if(bg){
      document.body.style.backgroundImage = `url('${bg.url}')`;
    }
  }, [bg])

  return null;
}

2. Explanation

Your code is not working because just after fetchPhoto() is executed and resolved, React did not yet re-render the components (update the state), therefore bg is still null.

CodePudding user response:

Do you need the state for something else? If not, you could avoid it:

function App() {
    
  useEffect(() => {
    const fetchPhoto = async () => {
      const dat = await fetch(`https://api.nasa.gov/planetary/apod?api_key=${apiKey}`);
      const data = await dat.json();
    
      if (data) {
        document.body.style.backgroundImage = `url('${data.url}')`;
      }
    }

    fetchPhoto();
  }, [])

  return null;
}
  • Related