Reputation: 526
What I have to achieve is to show the data obtained as response from api in sorted order from first render itself.
This is how I'm using useEffect hooks:-
useEffect(()=>{
async function fetchProject() {
await axios.post(envurls.wv+'/show_project',{
params:{
authtoken:authtoken,
user:user
}
}).then((response)=>{
console.log('Res', response.data);
setShowProject(response.data)
}).catch((error)=>{
console.log(error)
})
}
fetchProject();
},[]);
useEffect(() => {
showProject.length> 0 && sortArray();
}, []);
const sortArray = ()=> {
const sortProperty = 'timestamp';
sorted = [...showProject].sort((a, b) => (a[sortProperty] > b[sortProperty] ? -1 : 1))
console.log("Project", showProject);
console.log("Sorted Data", sorted);
setShowProject(sorted);
};
But on first render, it is not sorting data as showProject array is empty. So, I'm getting Project and Sorted Data as empty array on console.
And If I provide showProject in useEffect like this:-
useEffect(() => {
showProject.length> 0 && sortArray();
}, [showProject]);
Then it is displaying sorted data for the first render itself but Project and Sorted Data are geetind displayed for n number of times in console.
Upvotes: 0
Views: 1009
Reputation: 622
As far as I'm aware, the only way to get your "sorted data" on the first render is by passing the sorted data into the component through props. You are also needlessly updating your showProject
twice which will cause unnecessary rerenders and @Asaf Aviv's answer is a good work around to that.
The best way to call a function only after getting data from the backend
is to put the function call inside of the .then()
callback or inside of and async
function after an await. Right now your sortArray()
is NOT doing either of those, it's outside the scope of your async function
and await
has no effect on it. The component renders, checks the showProject.length> 0
condition, and if the condition is met it runs the function.
Also, you don't need to use .then()
or .catch()
inside of an async function, this is a more typical way to do it:
async function fetchProject() {
try {
let response = await axios.post(envurls.wv + "/show_project", {
params: {
authtoken: authtoken,
user: user
}
});
// everything past here runs ONLY AFTER getting a response back from axios.post
setShowProject(response.data)
} catch (err) {
console.log(err);
}
}
Upvotes: 0
Reputation: 11760
You can use useMemo and set the dependencies to the data in state and the sorting parameters.
useMemo
will call that function when one of the dependencies has changed exactly like useEffect
, but this time it will return the value we return from that function.
This way we don't touch the original state and just sort it after changes
useEffect(() => {
async function fetchProject() {
const { data } = await axios.post(envurls.wv + "/show_project", {
params: {
authtoken: authtoken,
user: user
}
});
setShowProject(data);
}
fetchProject().catch(e => /* handle error here */);
}, []);
const sorted = useMemo(() => {
const sortProperty = "timestamp";
// use the sorting parameters here
return [...showProject].sort((a, b) =>
a[sortProperty] > b[sortProperty] ? -1 : 1
);
}, [showProject, sortType]);
console.log(sorted);
Upvotes: 1