Home > Blockchain >  React Typescript how to stop axios/fetch calls from making multiple calls at one time
React Typescript how to stop axios/fetch calls from making multiple calls at one time

Time:02-24

I am trying to connect my site with the rapidAPI using axios/fetch. I have multiple components I need to make, so I need to keep my call numbers low. That being said, I am a little new to React calls and both my axios and fetch calls are making the same API call multiple times, sucking up my API calls in no time (500 in a few minutes of trying to fix, lol). I'm not sure how to change my code up to work with async/await, and could use some help if that is the best solution. I've tried to just use cancelTokens, but this doesn't do the trick either. Below is my code using cancelTokens with a timeout. I know this is NOT a good and efficient way to remedy this problem, and need help to fix what I feel is an easy fix that just hasn't clicked in my head yet. Thank you so much in advance! here is my Stock.tsx component, which in the end grabs the stock ticker price:

import React from "react";
import "../styles/Stock.css";
import axios from "axios";
import loader from "../graphics/loading.gif";

const { useState } = React;

function Stock() {
  const [price, setPrice] = useState("0");
  let options: any;
  const cancelToken = axios.CancelToken;
  const source = cancelToken.source();
  options = {
    cancelToken: source.token,
    method: "GET",
    url: "https://yh-finance.p.rapidapi.com/stock/v2/get-summary",
    params: { symbol: "AAPL", region: "US" },
    headers: {
      "x-rapidapi-host": "yh-finance.p.rapidapi.com",
      "x-rapidapi-key": "nonono:)",
    },
  };

  axios
    .request(options)
    .then(function (response) {
      console.log(response.data);
      setPrice(response.data.price.regularMarketPrice.fmt.toString());
    })
    .catch(function (error) {
      console.error("Error getting price: ", error);
    });
//i know, this is bad
  setTimeout(() => {
    source.cancel("TIME");
  }, 2000);
  return (
    <>
      {price === "0" ? (
        <div>
          <img src={loader} alt="loading" className={"loader"} />
        </div>
      ) : (
        <div>AAPL: {price}</div>
      )}
    </>
  );
}

export default Stock;

CodePudding user response:

If your network request is supposed to be made just once when the component is mounted, then this is the use case for useEffect with an empty dependency array:

If you want to run an effect [...] only once (on mount [...]), you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.

import React, { useEffect } from "react";

// Within the body of your React functional component:
useEffect(() => {
  axios.request(options) // etc.
}, []); // 2nd argument is the dependency array, here empty

CodePudding user response:

The key is the useEffect method. useEffect is a function which it is executed when one of the variables have changed.

useEffect(() => {
  axios...
}, []);

If the second param is an empty list (variables list), the method will be executed only once.

One improvement would be to use useEffect without the second parameter, and check if you have already the data. If not, you will be calling every time is rendering only if you don't have the data.

useEffect(() => {
 if (!loading && !data) {
   setLoading(true);
   axios....then(() => {
     ....
     setLoading(false);
   }).catch(function (error) {
        ....
        setLoading(false);
   });
 }
});

I hope I've helped you

CodePudding user response:

Try this solution with refs

import React,{useRef,useEffect} from "react";
import "../styles/Stock.css";
import axios from "axios";
import loader from "../graphics/loading.gif";

const { useState } = React;

function Stock() {
  const stockRef = useRef(false);
  const [price, setPrice] = useState("0");
  let options: any;
  const cancelToken = axios.CancelToken;
  const source = cancelToken.source();
  options = {
    cancelToken: source.token,
    method: "GET",
    url: "https://yh-finance.p.rapidapi.com/stock/v2/get-summary",
    params: { symbol: "AAPL", region: "US" },
    headers: {
      "x-rapidapi-host": "yh-finance.p.rapidapi.com",
      "x-rapidapi-key": "nonono:)",
    },
  };

  const fetchData = () => {
    if (stockRef && stockRef.current) return;
    stockRef.current = true;
    axios
      .request(options)
      .then(function (response) {
        console.log(response.data);
        setPrice(response.data.price.regularMarketPrice.fmt.toString());
    })
    .catch(function (error) {
      console.error("Error getting price: ", error);
    });

    stockRef.current = false;
  }
 }
  
 //i know, this is bad
  setTimeout(() => {
    source.cancel("TIME");
  }, 2000);

    useEffect(() => {
    fetchData();
  },[])

  return (
    <>
      {price === "0" ? (
        <div>
          <img src={loader} alt="loading" className={"loader"} />
        </div>
      ) : (
        <div>AAPL: {price}</div>
      )}
    </>
  );
}

export default Stock;
  • Related