Make React JS await for a async func to complete before running

I’m trying to make react not load until after an axios get requests finishes. I’m pretty rough on react all around, so sorry in advance.

I’m getting an array of objects const { dogBreedsTest } = useApplicationData()

And I need it to be the default value of one of my states const [dogBreeds, updateDogBreeds] = useState(dogBreedsTest);

However, I’m getting an error that my value is coming up as null on the first iteration of my app starting. How can I ensure that my value has completed my request before my app tries to use it?

Here is how I am getting the data for useApplicationData()

const [dogBreedsTest, setDogBreeds] = useState(null);

  const getDogBreeds = async () => {
    try{
      const { data } = await axios.get('https://dog.ceo/api/breeds/list/all')
      if(data) {
        const newDogList = generateDogsArray(data['message'])
        const generatedDogs = selectedDogs(newDogList)
        setDogBreeds(generatedDogs)
        
      }
    } catch(err) {
      console.log(err);
    }
  }
  
  useEffect(() => {
    getDogBreeds()
  }, []);

  return {
    dogBreedsTest,
    setDogBreeds
  }

And I am importing into my app and using:

import useApplicationData from "./hooks/useApplicationData";

const { dogBreedsTest } = useApplicationData()
  const [dogBreeds, updateDogBreeds] = useState(dogBreedsTest[0]);
  const [breedList1, updateBreedList1] = useState(dogBreedsTest[0])

function handleOnDragEnd(result) {
    if (!result.destination) return;

    const items = Array.from(dogBreeds);
    const [reorderedItem] = items.splice(result.source.index, 1);
    items.splice(result.destination.index, 0, reorderedItem);
    for (const [index, item] of items.entries()) {
      item['rank'] = index + 1
    }
    updateDogBreeds(dogBreedsTest[0]);
    updateBreedList1(dogBreedsTest[0])
  }
return (
<div className="flex-container">
      <div className="App-header">
          <h1>Dog Breeds 1</h1>
          <DragDropContext onDragEnd={handleOnDragEnd}>
            <Droppable droppableId="characters">
              {(provided) => (
                <ul className="dogBreeds" {...provided.droppableProps} ref={provided.innerRef}>
                  {breedList1?.map(({id, name, rank}, index) => {
                    return (
                      <Draggable key={id} draggableId={id} index={index}>
                        {(provided) => (
                          <li ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
                            <p>
                              #{rank}:  { name }
                            </p>
                          </li>
                        )}
                      </Draggable>
                    );
                  })}
                  {provided.placeholder}
                </ul>
              )}
            </Droppable>
            </DragDropContext>
        </div>
)

error: TypeError: Cannot read property 'map' of null (I am mapping the data later in the program)

Answer

const getDogBreeds = async () => {
  try {
    const { data } = await axios.get('https://dog.ceo/api/breeds/list/all')
      if(data) {
        const newDogList = generateDogsArray(data['message'])
        const generatedDogs = selectedDogs(newDogList)
        setDogBreeds(generatedDogs)
      }
  } catch(err) {
      console.log(err);
  }
}
  
useEffect(() => {
  getDogBreeds() // -> you are not awaiting this
}, []);

Do this instead

useEffect(() => {
  axios.get('https://dog.ceo/api/breeds/list/all')
    .then(res => {
      const newDogList = generateDogsArray(res.data['message']);
      const generatedDogs = selectedDogs(newDogList);
      setDogBreeds(generatedDogs);
    })
    .catch(err => console.log(err));
}, []);

I know this looks awful, but I don’t think you should use async/await inside useEffect

Use this in your application

useEffect will update whenever dogBreedsTest is changed. In order to make it work, start with null values and update them to the correct initial values once your async operation is finished.

const { dogBreedsTest } = useApplicationData();
const [dogBreeds, updateDogBreeds] = useState(null);
const [breedList1, updateBreedList1] = useState(null);

useEffect(() => {
  updateDogBreeds(dogBreedsTest[0]);
  updateBreedList1(dogBreedsTest[0]);
}, [dogBreedsTest]);