vasilis 123
vasilis 123

Reputation: 665

unable to display fetched API data in react

I'm a complete beginner in react and I am fetching data from https://www.boredapi.com/documentation#endpoints-price . With http://www.boredapi.com/api/activity/ you get a random activity object in the format of

{
    "activity": "Learn Express.js",
    "accessibility": 0.25,
    "type": "education",
    "participants": 1,
    "price": 0.1,
    "link": "https://expressjs.com/",
    "key": "3943506"
} 

I'm trying to fetch 10 of these objects using react hooks and then display them . However with my code below when I try to fetch and display a single activity name nothing happens . I initialize an array with hooks and I want to append a new object each time I fetch

useFetch.js to fetch an activity

import {useState , useEffect} from 'react';


export default function useFetch(){
  const [activities,setActivities] = useState([]);
  const getActivities = async () =>{
    for(let k=0;k<10;k++){
      let response = await fetch("http://www.boredapi.com/api/activity/");
      let result = await response.json();
      setActivities((oldstate)=>[...oldstate,result])
     }
  }
  useEffect(()=>{
    getActivities();
  }, [])

  return {activities};
}

AcitivityBar.js to display activities

    import React from 'react';
import useFetch from './useFetch';


export default function ActivityBar(){
  const {activities} = useFetch();
  console.log(activities)
  return (
    <div className="activities-container">
        {
          (activities.map((a , index)=>{
            return <h1 key = {index}>hi</h1>
          }))
        }
    </div>
  );
}

Upvotes: 1

Views: 374

Answers (3)

ecoplaneteer
ecoplaneteer

Reputation: 1984

You could use Promise.all to wait for multiple requests in parallel:

This will show results simultaneously not one after one.

import { useState, useEffect } from 'react'

export default function useFetch() {
  const [activities, setActivities] = useState([])

  const getActivities = async () => {
    let arr = []
    for (let k = 0; k < 10; k++) {
      arr[k] =  new Promise(async (resolve, reject) => {
        fetch('http://www.boredapi.com/api/activity/').then((response) => {
          resolve(response.json())
        })
      })
    }
    Promise.all(arr).then((results) => {
      setActivities(results)
    })
  }
  useEffect(() => {
    getActivities()
  }, [])

  return { activities, getActivities }
}

Upvotes: 1

Aadil Mehraj
Aadil Mehraj

Reputation: 2614

Make sure you append new activities properly from the response using spread operator, like this:

let response = await fetch("http://www.boredapi.com/api/activity/");
let activity = await response.json();
setActivities(prev => [...prev, activity]);

EDIT: The main issue is with the scoping, the activities is not persisted across render. You should consider using prev value.

Upvotes: 1

Kevin
Kevin

Reputation: 267

You should probably change your iteration to something like this:

const getActivities = async () =>{
    for(let k=0;k<10;k++){
      let response = await fetch("http://www.boredapi.com/api/activity/");
      let result = await response.json();
      setActivities(prev => [...prev, result])
     }
  }

the useState also has a function input that returns the actual value. You shouldn't rely on the activities since that is always an empty array when all the items get loaded at once

Upvotes: 1

Related Questions