Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
Im new at React, I was trying to make weather website. I want to get the visitor’s IP first, then get the city location, and then get the weather conditions directly through Openweather. Here is my code, I hope someone can help me answer how to complete this website, Thank you
import { useState, useEffect } from "react";
import axios from "axios";
require("dotenv").config();
function IpGet() {
const [ip, setIP] = useState("");
const [countryName, setcountryName] = useState("");
const [cityName, setcityName] = useState("");
const [countryCode, setcountryCode] = useState("");
const [countryStateName, setcountryStateName] = useState("");
const WeatherKey = process.env.REACT_APP_WEATHERKEY;
const getData = async () => {
const res = await axios.get("https://geolocation-db.com/json/");
setIP(res.data.IPv4);
setcountryName(res.data.country_name);
setcityName(res.data.city);
setcountryCode(res.data.country_code);
setcountryStateName(res.data.state);
};
// const getWeather = async () => {
// const WeatherUrl = await axios.get(
// `https://api.openweathermap.org/data/2.5/weather?q=${cityName},${countryStateName}&appid=${WeatherKey}`
// );
// };
useEffect(() => {
getData();
}, []);
return (
<div className="IpGet">
<h4>{ip}</h4>
<h4>{countryName}</h4>
<h4>{countryCode}</h4>
<h4>{countryStateName}</h4>
<h4>{cityName}</h4>
</div>
);
}
export default IpGet;
The question is vague but here is a bit of a guess.
A few tips to start with:
You probably don't need axios for most front-end solutions. It is just an extra dependency. Use the fetch API instead.
Keep your variable names consistent - setCountryName instead of setcountryName.
The useMemo hook will prevent a function from being created on every render. You can pass the second argument of a dependency array that contains variables. If any of those variables change, useMemo will recalculate that function.
Now to the code. You can give useEffect the second argument of an array of variables. If any of these variables change, the effect will run the callback function provided as the first arg. useEffect will also always run once when the component mounts.
Create a second effect that runs when you get the data needed to make the weather API call.
All things above considered, your code might now look like this (untested):
import { useState, useEffect } from 'react';
require('dotenv').config();
function IpGet() {
const [ip, setIP] = useState('');
const [countryName, setCountryName] = useState('');
const [cityName, setCityName] = useState('');
const [countryCode, setCountryCode] = useState('');
const [countryStateName, setCountryStateName] = useState('');
const weatherKey = process.env.REACT_APP_WEATHERKEY;
// useMemo to avoid recreating this function on every render
const getData = React.useMemo(() => async () => {
const res = await fetch('https://geolocation-db.com/json/');
setIP(res.data.IPv4);
setCountryName(res.data.country_name);
setCityName(res.data.city);
setCountryCode(res.data.country_code);
setCountryStateName(res.data.state);
});
const getWeather = React.useMemo(() => async () => {
if (!cityName || !countryStateName || !weatherKey) return;
const weatherUrl = `https://api.openweathermap.org/data/2.5/weather?q=${cityName},${countryStateName}&appid=${weatherKey}`;
const weatherData = await fetch(weatherUrl);
// Do something with weatherData here... set to some state or something.
});
useEffect(() => {
getData();
}); // No dependency array, so this will only run once when the component mounts
useEffect(() => {
getWeather();
}, [cityName, countryStateName]); // This will trigger the callback when any of these variables change.
return (
<div className='IpGet'>
<h4>{ip}</h4>
<h4>{countryName}</h4>
<h4>{countryCode}</h4>
<h4>{countryStateName}</h4>
<h4>{cityName}</h4>
</div>
);
}
export default IpGet;
Related
Today I wanted to test axios.all, so I made the script that you can see below only there is a small problem. The script allows me to retrieve data from the API when I run it, however there is something I don't understand. The functions setInterval execute an action every 30 seconds as requested but it displays exactly the same values and when I reload the page manually it's the same a new console.log appears but with exactly the same data. My goal is of course that once the first request is done, other requests can be done to update the data, I have the impression that the data is stored in a cache and that it never expires
Thanks for your help
Here is my script :
import logo from "./logo.svg";
import "./App.css";
import axios from "axios";
import { useEffect, useState } from "react";
const App = () => {
const [uniData, setUniDataTop] = useState([]);
const [susData, setSusDataSec] = useState([]);
const [Ptest, setPtest] = useState([]);
const fetchData = () => {
const uniAPI = "https://api.coingecko.com/api/v3/exchanges/uniswap/tickers";
const susAPI =
"https://api.coingecko.com/api/v3/exchanges/sushiswap/tickers";
const getUniPrice = axios.get(uniAPI);
const getSusPrice = axios.get(susAPI);
axios.all([getUniPrice, getSusPrice]).then(
axios.spread((...allData) => {
const priceuni = allData[0].data.tickers;
const pricesus = allData[1].data.tickers;
console.log(pricesus);
console.log(priceuni);
const unitest = priceuni?.find(
(element) =>
element.trade_url ===
"https://app.uniswap.org/#/swap?inputCurrency=ETH&outputCurrency=0xc669928185dbce49d2230cc9b0979be6dc797957"
);
const unitest2 = unitest?.converted_last.usd;
const sustest = pricesus?.find(
(element) =>
element.trade_url ===
"https://app.sushi.com/swap?inputCurrency=0x64aa3364f17a4d01c6f1751fd97c2bd3d7e7f1d5&outputCurrency=0x6b175474e89094c44da98b954eedeac495271d0f"
);
const sustest2 = sustest?.converted_last.usd;
const unitable = [unitest2, "ETH/USDT", "UniSwap"];
const sustable = [sustest2, "ETH/USDT", "Uniswap"];
var number = [unitable, sustable];
number.sort();
const percentage = [(number[1][0] - number[0][0]) / number[1][0]] * 100;
setUniDataTop(number[1][0]);
setSusDataSec(number[0][0]);
setPtest(percentage);
})
);
};
useEffect(() => {
fetchData();
}, []);
setInterval(fetchData, 30 * 1000);
return (
<>
{uniData}
<br />
{susData}
<br />
{Ptest}%
</>
);
};
export default App;
#Konrad is correct. You can't call setInterval outside of useEffect, in your implementation on the first render setInterval run the fetch which will call the api. Then it will update the state which will in return re-render the page and then the setInterval run again and update the state and this will go on until the application crashes due to lack of memory.
Instead, you can put the setInterval inside of the useEffect. This way the setInterval is created once when the component mounts for the first time and is not created again and again when the component re-renders.
useEffect(() => {
const timeout = setInterval(() => {
fetchData();
}, 30 * 1000);
return () => {
// clears the interval when the unmounts
clearInterval(timeout);
};
}, []);
// setInterval(fetchData, 30 * 1000) // remove this
And since your data in the state is most likely number or string, you can remove the [] from the useState([]) too.
Hope this helps.
How can I create a component for Axios that I can use in different places with different values ??
I got stuck, what should I do?
This is what I have achieved so far
thank you for Helping
import axios from "axios";
const Axios = (props) => {
const [posttitle, postbody] = useState([]);
const [postuserid, postid] = useState([]);
const fetchData = () => {
const { postbodyapi } = props.postbodyapi;
const postuseridapi = "https://nba-players.herokuapp.com/players/james/lebron";
const getbody = axios.get(postbodyapi);
const getuseid = axios.get(postuseridapi);
axios.all([getbody, getuseid]).then(axios.spread((...allData) => {
const databody = allData[0].data.first_name;
const datauseid = allData[1].config.url;
postbody(databody);
postid(datauseid);
}))
}
useEffect(() => {
fetchData()
}, [])
return (
<div className="App">
{posttitle}
<img src={postuserid} alt="asd"/>
</div>
);
}
export default Axios;
You should create a custom hook.
Create a hook called for example useAxios and hold only the fetching method inside of it, and the return state from that hook should be just data.
you can make it so it takes params like "URL, data, method", or make a few smaller hooks like useAxiosGet, useAxiosPost.
If you make a few smaller it will be easier to read and change something if needed.
Here is how I did it, an example of one specific Axios custom hook, use this for example to see how to build it.
useGetCar.js // custom axsios hook
import axios from 'axios';
const useGetCar = async (url, id) => {
const result = await axios.post(url, {id: id});
return result.data[0];
}
export default useGetCar
car.js // page component that displays data
import useGetCar from "#hooks/useGetCar";
let car_id = 1; // some that i send to api
// this function here is not exact from my code,
//but I just wanted to provide you an example.
// I didn't include my original code because it is
//from next.js app and I don't want to confuse u with that
async function getData() {
let car = await useGetCar(`http://localhost/get_car.php`, car_id);
return car;
}
Hope you understood what I'm saying, and I did not confuse you.
Feel free to ask anything if you don't understand something clearly.
Happy coding.
When I try to execute the following react code, the axios.get() executed multiple times.
I have attached the screenshot of the log. Console Logs.
Can anyone please help me regarding this.
const CaskList = () =>{
const [casklist,getCaskList] = useState('');
const [searchCaskName, getCaskForSearch] = useState('');
const [searchResultCaskName, setSearchResultCaskName] = useState('');
const getCaskForSearchFromInput = (event) =>{
console.log(event.target.value);
getCaskForSearch(event.target.value);
};
useEffect(()=>{
const func = async() =>{
const resultCasks = await axios.get('http://localhost:3001/getAllApps');
const actualData = resultCasks.data;
console.log("**********************" + actualData);
getCaskList(actualData);
}
func();
})
const caskToBeRendered = [];
for(let i=0;i<casklist.length;i++){
caskToBeRendered.push(<Cask allCasks={casklist[i]} >);
};
const options = {
includeScore: false,
findAllMatches : true,
threshold : 0.3
};
const fuse = new Fuse(casklist,options);
const result = fuse.search(searchCaskName);
setSearchResultCaskName(result);
return (
<div>
{caskToBeRendered}
</div>
);
}
you need to pass a second argument to hook useEffect. You can read about that
If you want to run an effect and clean it up only once (on mount and
unmount), 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. This isn’t handled as a special
case — it follows directly from how the dependencies array always
works.
useEffect(()=>{
const func = async() =>{
const resultCasks = await axios.get('http://localhost:3001/getAllApps');
const actualData = resultCasks.data;
getCaskList(actualData);
}
func();
},[])
You need to add a empty dependency array.
If you want to fire useEffect once on initial mount only. Like
useEffect(() => {
//your code goes here
}, []);
If you want useEffect to fire on initial mount and every re-render, you don't pass any dependency array. Like
useEffect(() => {
//your code goes here
});
I've made a really simple React hook. That's something seen on many guides and websites:
import { useEffect, useState } from 'react';
import axios from 'axios';
export const useFetchRemote = (remote, options, initialDataState) => {
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, options);
setData(result.data);
};
fetchData();
}, [remote]);
return data;
};
Example usage:
import { useFetchRemote } from '../utils';
export const UserList = () => {
const users = useFetchRemote('/api/users', {}, []);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
This is working. If I understand correctly:
With no dependencies like useEffect(() => { /*...*/ }), setting the state into the function would trigger a re-render, calling useEffect again, in an infinite loop.
With empty dependencies like useEffect(() => { /*...*/ }, []), my function will be called only the "very first time" component is mounted.
So, in my case, remote is a dependency. My function should be called again if remote changes. This is true also for options. If I add also options, the infinite loop starts. I can't understand... why this is happening?
export const useFetchRemote = (remote, options, initialDataState) => {
// ...
useEffect(() => {
// ...
}, [remote, options]);
// ...
};
The infinite loop is caused by the fact that your options parameter is an object literal, which creates a new reference on every render of UserList. Either create a constant reference by defining a constant outside the scope of UserList like this:
const options = {};
const initialDataState = [];
export const UserList = () => {
// or for variable options instead...
// const [options, setOptions] = useState({});
const users = useFetchRemote('/api/users', options, initialDataState);
return (
<ul>
{users.map(user => <li key={user.id}>{user.name}</li>}
</ul>
);
}
or if you intend the options parameter to be effectively constant for each usage of the userFetchRemote() hook, you can do the equivalent of initializing props into state and prevent the reference from updating on every render:
export const useFetchRemote = (remote, options, initialDataState) => {
const [optionsState] = useState(options);
const [data, setData] = useState(initialDataState);
useEffect(() => {
const fetchData = async () => {
const result = await axios.get(remote, optionsState);
setData(result.data);
};
fetchData();
}, [remote, optionsState]);
// ---------^
return data;
};
This second approach will prevent a new fetch from occuring though, if the options are dynamically changed on a particular call site of useFetchRemote().
I watched a Youtube video and I made my own recipe app. I'm a beginner at React.js and I've been solving this problem for about 2 days. Seems that i cant pass the value of my state to useEffect hook. Here's an example of my code. The error says
"React Hook useEffect has a missing dependency: 'query'. Either include it or remove the dependency array" and everytime I typed in the input box it triggers the useEffect hook. Thank you and your help is very much appreciated.
const [recipes, setRecipes] = useState([]);
const [search, setSearch] = useState('');
const [query, setQuery] = useState('steak');
const updateSearch = e => {
setSearch(e.target.value);
console.log(search)
}
const getSearch = e => {
e.preventDefault();
setQuery(search);
}
useEffect(() => { // error Is from the Query variable
const GetRecipe = async () => {
const APP_ID = "3834705e";
const APP_KEY = "c23e9514f82c2440abf54b21edd4c3dc";
const res = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await res.json();
setRecipes(data.hits);
}
GetRecipe();
},[getSearch]) //this triggers everytime I typed in the input box which is not it is supposed to
return(
<div className='recipelist'>
<form onSubmit={getSearch}>
<input type="search" onChange={updateSearch}/>
<button type='submit'>submit</button>
</form>
As the error tells you, when using a useEffect hook, that hook can receive two arguments, the first one is the handler effect and the second one is an array containing all dependencies that effect will use, so as you are using the query state into the http url, you need to pass that dependency into the array, so could be something like this.
useEffect(() => { // error Is from the Query variable
const GetRecipe = async () => {
const APP_ID = "3834705e";
const APP_KEY = "c23e9514f82c2440abf54b21edd4c3dc";
const res = await fetch(`https://api.edamam.com/search?q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await res.json();
setRecipes(data.hits);
}
GetRecipe();
},[getSearch, query])
so what is actually doing the array dependency, as React docs says, array dependency it's used to check if the effect should execute again based on its dependencies, so in your code everything you type something, getSearch method is re-creating again and again in memory, so it will check the last getSearch function that it took and compare it with the new ones, so it will check as equally checker like fn1 === fn2, so due to both function are exactly the same, both keeps different space in memory, so both are different objects, check this docs to understand the concept.
Here you have the react docs too