Home > Blockchain >  axios doesnt fetch on refresh, only on first render
axios doesnt fetch on refresh, only on first render

Time:05-08

So I've been struggling for a while with retrieving data from APIs and or retrieving local json files. I am using React axios but even with the normal fetch method I am having the same issues. When I fetch the endpoint and save the code, my jsx refreshes and the data appears on the screen but then when I refresh the page, it's no longer there and doesn't appear when I refresh again and again. I have no idea what I am doing wrong. I tried to retrieve the data on the parent and set it as props but still the same problem.

My child component:

import React, { useEffect, useState } from 'react';

import './Card.scss';

import axios from 'axios';

import { ellipsisIcon } from '../../constants/images';

import dataJson from './data.json';

const Card = ({ name, color, icon, currentTime }) => {
  const [data, setData] = useState([]);

  const [daily, setDaily] = useState([]);
  const [weekly, setWeekly] = useState([]);
  const [monthly, setMonthly] = useState([]);

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios.get('data.json');
      setData(result.data);
      setData(
        data.filter((item) => {
          return item.title === name;
        }),
      );

      setDaily(data[0].timeframes.daily);
      setWeekly(data[0].timeframes.weekly);
      setMonthly(data[0].timeframes.monthly);
    };
    fetchData();
  }, []);

  return (
    <div className="card" style={{ backgroundColor: `${color}` }}>
      <img src={icon} alt={`${name} icon`} />
      <div className="card__container bg-blue">
        <div className="card__top-container flex">
          <p className="text-white ">{name}</p>
          <div className="card__top__elipse-container">
            <img src={ellipsisIcon} alt="ellipsis" />
          </div>
        </div>
        <div className="card__bottom-container">
          {currentTime === 0 && (
            <>
              <h1 className="fs-900 text-white">{daily.current}hrs</h1>
              <div className="card__bottom__prev-container">
                <p className="text-accent ">
                  Yesterday -<span>{daily.previous}hrs</span>
                </p>
              </div>
            </>
          )}
          {currentTime === 1 && (
            <>
              <h1 className="fs-900 text-white">{weekly.current}hrs</h1>
              <div className="card__bottom__prev-container">
                <p className="text-accent ">
                  Last Week -<span>{weekly.previous}hrs</span>
                </p>
              </div>
            </>
          )}
          {currentTime === 2 && (
            <>
              <h1 className="fs-900 text-white">{monthly.current}hrs</h1>
              <div className="card__bottom__prev-container">
                <p className="text-accent">
                  Last Month -<span>{monthly.previous}hrs</span>
                </p>
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
};

export default Card;

My App (Parent):

import { useState, useEffect } from 'react';
import Card from './components/Card/Card';

import {
  pbImage,
  ellipsisIcon,
  exerciseIcon,
  playIcon,
  careIcon,
  socialIcon,
  studyIcon,
  workIcon,
} from './constants/images';

const cards = [
  {
    name: 'Exercise',
    color: 'hsl(var(--clr-exercise))',
    icon: exerciseIcon,
  },
  {
    name: 'Play',
    color: 'hsl(var(--clr-play))',
    icon: playIcon,
  },
  {
    name: 'Self Care',
    color: 'hsl(var(--clr-care))',
    icon: careIcon,
  },
  {
    name: 'Social',
    color: 'hsl(var(--clr-social))',
    icon: socialIcon,
  },
  {
    name: 'Study',
    color: 'hsl(var(--clr-study))',
    icon: studyIcon,
  },
  {
    name: 'Work',
    color: 'hsl(var(--clr-work))',
    icon: workIcon,
  },
];

function App() {
  const [selectedTime, setSelectedTime] = useState(2);
  return (
    <div className="app bg-dark">
      <div className="main__container grid">
        <div className="side__card-container">
          <div className="side__card__top flex">
            <div className="side__card__top__pb-container">
              <img
                src={pbImage}
                alt="pb"
                className="side__card__top__pb-image pb-image"
              />
            </div>
            <div className="side__card__top__person-container">
              <p className="fs-600 text-accent">Report for</p>
              <h2 className="fs-800 text-white">Jeremy Robson</h2>
            </div>
          </div>
          <div className="side__card__bottom">
            <div>Daily</div>
            <div>Weekly</div>
            <div>Monthly</div>
          </div>
        </div>
        {cards.map((card, _index) => (
          <Card
            key={_index}
            name={card.name}
            color={card.color}
            icon={card.icon}
            currentTime={selectedTime}
          />
        ))}
      </div>
    </div>
  );
}

export default App;

CodePudding user response:

As I mentioned in the comments, states are updated asynchronously. So, you should be careful when you use a state immediately after setting its value. In your case, you shouldn’t use the data state because you are not sure that it has a value. Try changing to this.

  useEffect(() => {
    const fetchData = async () => {
      const result = await axios.get('data.json');
      const filteredData = result.data.filter((item) => {
          return item.title === name;
      })

      setData(filteredData);
      
      // make sure result data isn’t empty
      setDaily(result.data[0].timeframes.daily);
      setWeekly(result.data[0].timeframes.weekly);
      setMonthly(result.data[0].timeframes.monthly);
    };
    fetchData();
  }, []); // "[]" makes the useEffect callback only run after the first render
  • Related