Search code examples
javascriptreactjsasync-awaitreact-hooksuse-effect

How to call a function in useEffect only after getting data from backend?


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.


Solution

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