0

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.

10
  • 1
    Why does the sort array function need to be in a useEffect? Also, state filled by a fetch will always be the default state on the first render. Commented Apr 20, 2021 at 12:51
  • 1
    Can't you sort it upon receiving it? Commented Apr 20, 2021 at 12:52
  • Because, I have to sortData depending on other states too like sorting type 'asc' or 'desc'. So each time user toggle from asc to desc. sortArray should get called. So I'll pass [sortType] as second parameter here to useEffect of sortArray Commented Apr 20, 2021 at 12:53
  • If the useEffect relies on the state showProject then it should be put into the dependency array. Also, you're not passing anything to sortArray Commented Apr 20, 2021 at 12:54
  • I tried to pass showProject but it is showing data n number of times in console. I forget to add it here.. I just edited the code. Commented Apr 20, 2021 at 12:56

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

3 Comments

So You created a memo sorted but since its not a function what if want to pass sortProperty as an argument.
@AnkitJaishwal You save the sortProperty in state or pass it via props and include it in the dependencies array. This way when you update it useMemo will automatically re-run the function provided.
You can also just sort in render, but I think useMemo makes it cleaner and also will only run when needed
0

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);
  }
}
   

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.