this is my first time using react. im working on a basic weather app.
i have a problem with using multiple useEffect hook in order. i need to fetch both the geolocation and then the weather APP api in order when the page load.
but i the location keep returning null, here's the code
useEffect(()=>{
navigator.geolocation.getCurrentPosition((position) => {
setLatitude(position.coords.latitude)
setLongitude(position.coords.longitude)
});
},[])
useEffect(()=> {
axios.get(`${api.base}weather?lat=${latitude}&lon=${longitude}&units=metric&appid=${api.key}`).then
((response) => {
console.log(response.data)
})
},[])
any solution will be appreciated. thank you
For this you could make the second useEffect dependent on your latitude and longitude states:
useEffect(()=>{
axios.get(`${api.base}weather?lat=${latitude}&lon=${longitude}&units=metric&appid=${api.key}`).then
((response) => {
console.log(response.data)
})
},[latitute, longitude])
This will call the useEffect every Time the latitude or longitude states have changed.
Your useEffects are both running asynchronously after the first render. If you need them to be ordered, then you should run them together in the same useEffect and add your code to fetch the response within the success callback of getCurrentPosition.
See this example:
useEffect(() => {
const fetchData = async() => {
navigator.geolocation.getCurrentPosition((position) => {
setLatitude(position.coords.latitude)
setLongitude(position.coords.longitude);
const response = await axios.get(`${api.base}weatherlat=${position.coords.latitude}&lon=${position.coords.longitude}&units=metric&appid=${api.key}`);
});
});
}, []);
Note: setState is also asynchronous, hence why we use the return position directly for the axios fetch request.
An alternative to this is, as the other answer mentioned, having your second useEffect use [latitude, longitude] in the deps array but if you don't want to constantly fetch weather API data every single time the lat/long changes, then you can just do it this way to run this once on initial component mount.
Related
I have a handleRating function which sets some state as so:
const handleRating = (value) => {
setCompanyClone({
...companyClone,
prevRating: [...companyClone.prevRating, { user, rating: value }]
});
setTimeout(() => {
handleClickOpen();
}, 600);
};
I think also have a function which patches a server with the new companyClone values as such:
const updateServer = async () => {
const res = await axios.put(
`http://localhost:3000/companies/${companyClone.id}`,
companyClone
);
console.log("RES", res.data);
};
my updateServer function gets called in a useEffect. But I only want the function to run after the state has been updated. I am seeing my res.data console.log when I load my page. Which i dont want to be making reqs to my server until the comapanyClone.prevRating array updates.
my useEffect :
useEffect(() => {
updateServer();
}, [companyClone.prevRating]);
how can I not run this function on pageload. but only when companyClone.prevRating updates?
For preventing function call on first render, you can use useRef hook, which persists data through rerender.
Note: useEffect does not provide the leverage to check the current updated data with the previous data like didComponentMount do, so used this way
Here is the code example.
https://codesandbox.io/s/strange-matan-k5i3c?file=/src/App.js
While working with react useEffect hook, most of the example I came across in case of calling api data in useEffect hook for initiate the component is, calling api directly inside useEffce hook.
For instance,
useEffect(() => {
async function(){
const res = await axios.get(`https://jsonplaceholder.typicode.com/${query}`);
setData(res.data)
}
}, []);
But what about fetch data outside the hook with a method ? For instance,
const getData = () => {
async function(){
const res = await axios.get(`https://jsonplaceholder.typicode.com/${query}`);
setData(res.data)
}
useEffect(() => {
getData(); // here eslint shows an warning "Promise returned from setData is ignored"
}, [])
is there any specific reason for avoiding second example. If not what's the proper way to call api call function in useEffect hook with proper cleanup ?
In React component file
useEffect(() => {
loadData(query).then(setData)
}, [query])
crate another service file to serve data from API
in service file
export const loadData = async query => {
const res = axios.get(`https://jsonplaceholder.typicode.com/${query}`);
return res.data;
// You can put this API call in try catch to handle API errors
};
Creating a separate function for calling an api is a perfect example of loading data in useEffect. You can give it parameters if you would have a paginated endpoint and call it multiple times or add polling to the page to load the data by interval. I can only see benefits by creating a function for this.
useEffect(() => { fetch("./product.JSON") .then(res => res.json()) .then(data => setProducts(data)) }, [])
I'm using redux and trying to fetch data when my component did update.
I'm using useEffect hook to track posts update and getting the state with useSelector.
I'm having issues as the component is making infinite fetching requests instead of a single request.
Anyone knows how I can stop it from making infinite requests
and make a single request if posts updated?
my code:
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, [posts]);
image showing infinite fetching requests being made
From useEffect documentation
If you’re familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount, componentDidUpdate, and componentWillUnmount combined.
So, dispatch(getPosts(page)) will be called on component mount as well when any of the dependency provided get changed, this will make an API request and fetch the posts of this page. Which will eventually update the state.posts.posts once the API is successful. As, the same state.posts.posts is given as dependency to the useEffect hook this will trigger the function to get executed again and the cycle goes on.
For example if you want to make the API call and fetch new posts when there's a change in the page you should provide page as dependency instead of posts as shown below
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, [page]);
const posts = useSelector((state) => state.posts.posts);
useEffect(() => {
dispatch(getPosts(page));
}, []);
const updateNeeded = useSelector((state) => state.posts.updateNeeded);
useEffect(() => {
if (updateNeeded) {
dispatch(getPosts(page));
}
}, [updateNeeded]);
Change updateNeeded to true by a dispatch action when you want to fetch a new update, and when the update is fetched dispatch an action which will make this flag to false again.
I have no issues fetching the data from an API using useEffect. That works fine.
The problem is that I need to apply some processing to the data before I actually render it out (in this case, I need to shuffle the array that I receive).
I tried a million different ways, but I just can't find the right place to write that logic. Basically, it won't work anywhere.
What is the right way of going about this?
you can do everything with data before setState.
is useEffect when you fetched data from Api, shuffle it and then do setState.
little example:
useEffect(() => {
axios.get("http://example.com/data").then(response => {
const data = shuffle(response.data);
setState(data);
})
});
useEffect(() => {
const fetchData = async () => {
await axios.get("http://example.com/data").then(response => {
const data = shuffle(response.data);
setState(data);
});
};
fetchData();
return () => {
// Clean up func
}
}, []); //[] will prevent infinite API calling.
I am new in React.I just want to show records in the table and I fetch data like
const [allowances, setAllowances] = useState([]);
useEffect(() => {
fetch("http://127.0.0.1:8000/allowances/")
.then(data => {
return data.json();
})
.then(data => {
setAllowances(data);
})
.catch(err => {
console.log("error",err);
});
}, []);
Here how I check length=>
<div>{allowances.length}</div>
if i log the data in before setAllowances(data) ,data has 3 records.But when I check allowances.length, there are no records. its show like <div></div>. So I think this setAllowances is not working.right? what is wrong?
Update
This is my data of i logged before setAllowance=>
You are not setting the data correctly. As per the contents of data, it should be:
setAllowances(data.allowance);
For useEffect hooks to update every single time that your state changes, you need to pass it as a parameter. This happens by passing allowances within the square brackets after you set your callback to useEffect. Check out this link