why is my page reloading when re rendering a component - reactjs

I am doing a api call and then another for each of the object received in the first request.
I have a load more button at the end of my page to get more data added on the page.
Each time the button is clicked the data is fetched but the page reloads and then makes the UI go back to the top of the page instead of just appending the new data.
Not sure what would force the page to reload?
This is my useEffect hook:
useEffect(() => {
//this if/else statement is to find out if the page has been reloaded
if (performance.navigation.type === 1) {
console.log("This page is reloaded");
} else {
console.log("This page is not reloaded");
}
setLoading(true);
let cancel;
axios
.get(currentPageUrl, {
cancelToken: new axios.CancelToken((c) => (cancel = c)),
}).then((res) => {
setLoading(false);
setNextpageUrl(res.data.next);
setPokemons([...pokemons, ...res.data.results])
}).catch((e) => {
setErr(true)
})
}, [currentPageUrl]);
this is the function that would change the currentPageUrl :
const handleClick = () => {
setCurrentPageUrl(nextPageUrl);
}

After a lot of trial and error, the solution was simply to create a function that would handle the logic then put it inside the use effect.
const request = () => {
if (performance.navigation.type === 1) {
console.log("This page is reloaded");
} else {
console.log("This page is not reloaded");
}
setLoading(true);
let cancel;
axios
.get(currentPageUrl, {
cancelToken: new axios.CancelToken((c) => (cancel = c)),
}).then((res) => {
setLoading(false);
setNextpageUrl(res.data.next);
setPokemons([...pokemons, ...res.data.results])
}).catch((e) => {
setErr(true)
})
}
useEffect(() => {
request()
}, [currentPageUrl])

Related

Fetching an array of objects from POKEAPI using REACT.js and AXIOS {Answered}

I chose to start learning API handling with POKEAPI. I am at a step where I need to get the flavor_text of each pokemon (the description let's say) but I can't for some reason.
Here is the JSON structure for one specific pokemon: https://pokeapi.co/api/v2/pokemon-species/bulbasaur.
And here is my useEffect trying to get it. The line fetching the habitat works and displays on my website so I guess my issue comes from my map in setDescription but I can't be sure.
export default function Card({ pokemon }, { key }) {
const src = url + `${pokemon.id}` + ".png";
const [habitat, setHabitat] = useState(null);
const [descriptions, setDescriptions] = useState([]);
useEffect(() => {
const controller = new AbortController();
axios
.get(url2 + `${pokemon.name}`, { signal: controller.signal })
.then((res) => setHabitat(res.data.habitat.name))
.then((res) =>
setDescriptions(
res.data.flavor_text_entries.map((ob) => ob.flavor_text)
)
)
.catch((err) => {
if (axios.isCancel(err)) {
} else {
console.log("warning your useEffect is behaving");
}
});
return () => {
// cancel the request before component unmounts
controller.abort();
};
}, [pokemon]);
I tried console logging descriptions or descriptions[0] but that doesn't work.
Since you only setting up the state from those data and it doesn't looks like the second result need to wait the result from the first to perform you can do both on the same response/promise :
useEffect(() => {
const controller = new AbortController();
axios
.get(url2 + `${pokemon.name}`, { signal: controller.signal })
.then((res) => {
setHabitat(res.data.habitat.name))
const flavorTextEntrieList = res.data.flavor_text_entries;
setDescriptions(flavorTextEntrieList.map((ob) => ob.flavor_text))
})
.catch((err) => {
if (axios.isCancel(err)) {
} else {
console.log("warning your useEffect is behaving");
}
});
return () => {
// cancel the request before component unmounts
controller.abort();
};
}, [pokemon]);
Each then need to return something to be handled in next chainable then. Replace .then((res) => setHabitat(res.data.habitat.name)) with .then((res) => { setHabitat(res.data.habitat.name); return res; })

Wrong value of state displayed after refreshing a page from useEffect()

I have a problem with my page that fetch data from a server and displays it for the user. I am using the hook useEffect for it.
My problem is that the first time I visit a page the correct data are displayed (so from /home I go to /product1 I get correct information). But after manually refreshing my page /product1 even though the server is getting the correct information again, my state object of my page will not update again. Is there a way to fix this? Code below:
const [productInfo, setProductInfo] = useState({
saleStarted : null,
quantityPerSize : []
})
useEffect(() => {
const fetchdata = async () => {
setLoading(true);
const query = new db.Query('Products');
query.equalTo('productId', params.productId);
await query.find()
.then(async (response) => {
setdata(response[0].attributes);
})
.catch((err) => {
setError(err);
console.log(err);
})
.finally(() => {
setLoading(false);
});
}
if(isInitialized){
fetchdata();
}
}, [isInitialized]);
useEffect(() => {
const saleStartedInfo = async() => {
const options = {
link : url + params.contractId,
}
try{
let started = await db.find(options)
console.log(started); //returns true
setProductInfo({...productInfo, saleStarted : started});
}catch(e){
console.log(e);
}
}
const quantitySize = async() => {
let _quantityBySize = [];
for(let k = 0 ;k<data.numberOfSize;k++) {
let options = {
address : url + params.contractId,
}
try{
let quantitySize = await db.find(options);
_quantityBySize.push(quantitySize)
} catch(err) {
console.log(err);
}
}
console.log(_quantityBySize); // let's say returns [5,4,10] if product has 3 size
setContractInfo({...contractInfo, quantityPerSize : _quantityBySize})
}
if(isInitialized && data){
saleStartedInfo();
quantityMinted();
}
}, [data])
So after rendering this page the first time it will show sale started, and quantity 5, 4 and 10. After refresh it will show sale not started and quantity === [] (empty array)

Warning: Can't perform a React state update on an unmounted component in React native

I am getting data from axios.But sometime data is coming and some it is not showing data initially.
get-specific-salary-api.js:---
const AllSpecificSalaryAPI = (yearMonthFilter) => {
const [specificAllAPIData, setAllSpecificAPIData] = useState("");
const loginAuthToken = useSelector(
(state) => state.loginAuthTokenReducer.loginAuthToken
);
//NOTE:taking oved input and company selection code for dynamic parameter
const companyValue = useSelector(
(state) => state.changeCompanyReducer.company
);
const companyCode = companyValue[0];
const employeeId = companyValue[1];
useEffect(() => {
axios
.get(GET_ALL_SPECIFIC_SALARY, {
params: {
hev: companyCode,
year_month: yearMonthFilter,
oved: employeeId,
},
headers: {
Authorization: `Bearer ${loginAuthToken}`,
},
})
.then((response) => response.data)
.then((data) => setAllSpecificAPIData(data))
.catch((error) => {
if (error.status === 401) {
//NOTE: handling token expire
return ExpireAlertRestart();
} else {
Alert.alert(error.message);
}
});
}, []);
return {
specificAllAPI: specificAllAPIData,
};
};
export default AllSpecificSalaryAPI;
i am getting warning message for this.
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
at [native code]:null in dispatchAction
at src/api/get-specific-salary-api.js:32:12 in axios.get.then.then$argument_0
How can i solve this warning message?
In your useEffect, clean your states like so:
const [specificAllAPIData, setAllSpecificAPIData] = useState(null);
useEffect(() => {
return () => {
setAllSpecificAPIData(null);
};
}, []);
Please see a better explanation on how useEffect is working here
You are getting this because the component tries to update the state even when the component has unmounted.
To solve this, you can use an indicator variable that tells about the unmounting of the component. On unmounting, it will intercept the request of state update in between and cancel that.
let hasUnmounted = false;
useEffect(() => {
axios
.get(GET_ALL_SPECIFIC_SALARY, {
params: {
hev: companyCode,
year_month: yearMonthFilter,
oved: employeeId,
},
headers: {
Authorization: `Bearer ${loginAuthToken}`,
},
})
.then((response) => response.data)
.then((data) => {
if (hasUnmounted) return;
setAllSpecificAPIData(data)
})
.catch((error) => {
if (hasUnmounted) return;
if (error.status === 401) {
//NOTE: handling token expire
return ExpireAlertRestart();
} else {
Alert.alert(error.message);
}
});
return () => {
hasUnmounted = true;
}
}, []);
Check this link for implementation: https://codesandbox.io/s/happy-swartz-ikqdn?file=/src/updateErr.js
Note: go to https://ikqdn.csb.app/err in codesandbox's browser

GraphQL endCursor and React State

I'm trying to implement a pagination on my react fe. I'm calling my data on page load and setting the endCursor for the pagination into a react hook variable.
However when I click 'load more' button on my page it goes and fetches new data and should upset the endCursor with the new value retrieved... but it only does this once and then stops working. I'm sure I'm doing something silly but I can't figure out what.
Here's the code..
const LatestDrops = () => {
const [newArrivals, setNewArrivals] = useState([])
const [offset, setOffset] = useState('')
// Run on page load
useEffect(() => {
listNewArrivals()
},[])
// Fetch new arrivals
const listNewArrivals = () => {
getNewArrivals()
.then(data => {
if (data.error){
console.log('Error fetching new arrivals', data.error)
} else {
setNewArrivals(data.edges)
setOffset(data.pageInfo.endCursor)
}
})
.catch(e => console.log('Failed to fetch', e))
}
// Fetch more arrivals on click
const handleLoadMore = (e) => {
console.log('Fetching more with offset: ', offset)
getMarketPlaceListings(offset)
.then((data) => {
if (data.error){
console.log('Error fetching marketplace listings', data.error)
} else {
setNewArrivals(data.edges)
console.log('Page offset from server is: ', data.pageInfo.endCursor)
setOffset(data.pageInfo.endCursor)
}
})
}
return(
<section>
Cursor: {JSON.stringify(offset)}
<button onClick={e => handleLoadMore()}>
View all
</button>
</section>
)
}
export default LatestDrops
I've also tried throwing in the old state when updating it as suggested by another post ie:
setOffset(offset => data.pageInfo.endCursor)

How to stop useEffect from reloading my page every time?

For some reason my whole page reloads every time it updates the state after it gets it from the database. The page flickers and I end up at the top of the page. Why is this?
I update the entire state in other functions like sort(), that works perfect without reloading. I have put event.preventDefault() in every click handler so that shouldn't be the problem.
One of the great things with using React is to have a smooth UI without reloading so this is annoying.
function App() {
const [contacts, setContacts] = useState({ items: [] });
useEffect(() => {
axios
.get('http://localhost:5000/')
.then((result) => {
setContacts({ items: result.data });
})
.catch((err) => console.log(err));
}, []);
And this is the function that gets called:
const handleSubmit = (event) => {
event.preventDefault();
if (!id) {
axios
.post('http://localhost:5000/add/', input)
.then(() => {
setInput(emptyState);
})
.catch((err) => console.log(err));
} else {
axios
.post(`http://localhost:5000/update/${id}`, input)
.then(() => {
props.updateContact(input);
setInput(emptyState);
})
.catch((err) => console.log(err));
}
window.location = '/';
};
You need to put something in your [].
You can see that we passed props.name into the array in the second argument. This will now cause the effect to always run again when the name changes.
If you don't pass anything it will always update and will be useless.
useEffect(() => {
document.title = `Page of ${props.name}`
}, [props.name])

Resources