reactjspostaxiosgetcrud

Trying to get app to auto fetch from API on POST


Basically I'm working on creating a ToDo app with CRUD operations, however, when I POST or DELETE a document from MongoDB, I'd like my hook to auto fetch the results. I can feel that this is a simple fix and I've tried some weird things including useCallback but nothing seems to work. Here's my hook:

import { useCallback, useEffect, useState } from 'react';
import axios from 'axios';

export const useAPI = () => {
  const backendURL = '<InsertURL>.com/api/todos';
  const [retrievedData, setRetrievedData] = useState([]);

  //sends todo to database
  const postToDo = useCallback(async (newToDo) => {
    await axios
      .post(backendURL, newToDo)
      .catch((error) => console.log(error.message));
  }, []);

  //deletes a todo from the database
  const deleteToDo = async (todo) => {
    console.log(todo);
    await axios
      .delete(backendURL, todo)
      .catch((error) => console.log(error.message));
  };

  //gets todos from database
  useEffect(() => {
    const getToDos = async () => {
      await axios
        .get(backendURL)
        .then((fetchedData) => {
          setRetrievedData(fetchedData.data.todos);
        })
        .catch((error) => console.log(error.message));
    };
    getToDos();
  }, [postToDo]);

  return { retrievedData, postToDo, deleteToDo };
};

Basically, I want postToDo to be called and then for getToDos to execute immediately afterwards without having to refresh the page. I'll want to use this same technique to with deleteToDo.

Why useCallback? Because ESlinter told me to do it if I put postToDo in getToDos dependency. I thought if I put postToDo in the array it would update when the function was called, but that doesn't seem to be the case. I'm also worried about trying too many weird things because I added 30+ documents to my database on accident when it auto executed a bunch of times.


Solution

  • Abstracting away your React hooks, you can sequence asynchronous actions by using the .then promise syntax (as one example):

    const postToDos = async (newToDo) => {
        await axios
          .post(backendURL, newToDo)
          .catch((error) => console.log(error.message))
    }
    
    const getToDos = async () => {
          await axios.get(backendURL)
    }
    
    postToDos(newToDo).then(getToDos).then(fetchedData => {
        setRetrievedData(fetchedData.data.todos)
    })
    

    Or, you can combine the async/await syntax into a single function

    const postToDos = async (newToDo) => {
        await axios
          .post(backendURL, newToDo)
          .catch((error) => console.log(error.message))
    }
    
    const getToDos = async () => {
          await axios.get(backendURL)
    }
    
    const postAndGetToDos = async (newToDo) => {
        await postToDo(newToDo)
        var fetchedData = await getToDos()
        setRetrievedData(fetchedData.data.todos)
    }
    
    postAndGetToDos({/*new toDo object*/)