skip to Main Content

So I’m first making a call to my API to get and store user information, but then I need to make a second call to the API to get secondary information based on the response data from the first call.

I’ve tried a couple of ways to do this, and one of the ways does work, but not really in an acceptable way.

Here’s the relevant constants:

const thisUserID = localStorage.getItem('userID');

const [ listnames, setListNames ] = useState(null);
const [ listID, setListID ] = useState(null);
const [ listcontent, setListContent ] = useState(null);

The first call to the API:

useEffect(() => {
        axios.get(`/lists/user/${thisUserID}`)
            .then((response) => {
                console.log(response.data[0].listName);
                console.log(response.data[0]._id);
                setListNames(response.data[0].listName);
                setListID(response.data[0]._id);
            })
            .catch((err) => {
                console.error(err);
            });
    }, []);

I tried using a second useEffect() for the second call like so:

useEffect(() => {
        console.log("listID = " + listID)
        axios.get(`/listcontent/user/${listID}`)
            .then((response) => {
                console.log(response.data);
                setListContent(response.data);
            })
            .catch((err) => {
                console.error(err);
            });
    }, []);

But listID that was set in the first useEffect is null.

I tried using an if statement to only run when listID had a value like this:

if (listID) {
        console.log("listID = " + listID)
        axios.get(`/listcontent/user/${listID}`)
        .then((response) => {
            console.log(response.data);
            setListContent(response.data);
        })
        .catch((err) => {
            console.error(err);
        });
    }

This works and successfully calls the API and returns with the data I want, but it is making constant requests to the API multiple times a second, I just need it to make one single request.

So I tried to add a second condition to the if statement like this:

    let sss = 0;

    if (listID && sss < 1) {
        sss = 1;
        console.log("listID = " + listID)
        axios.get(`/listcontent/user/${listID}`)
        .then((response) => {
            console.log(response.data);
            setListContent(response.data);
        })
        .catch((err) => {
            console.error(err);
        });
        console.log("sss = " + sss)
    }

But it just kept making continuous calls to the API, even though the console log showed sss as 1 (or any number I set).

As a last attempt I tried adding a useEffect in the if statement, but that was never going to work and didn’t.

I haven’t been using React for very long, but I feel like there’s gotta be a relatively simple way I’m missing or just don’t know about to do this, because people surely do things like this often. If anyone can see where I’m making a mistake(s) or knows how I can go about solving this, I appreciate any help. If there’s any more information/code I can provide that could be helpful please let me know, thank you.

2

Answers


  1. Add ListId as a dependency in the second useEffect.

    useEffect(() => {
      console.log("listID = " + listID);
      if (listID) {
        axios
          .get(`/listcontent/user/${listID}`)
          .then((response) => {
            console.log(response.data);
            setListContent(response.data);
          })
          .catch((err) => {
            console.error(err);
          });
      }
    }, [listID]);
    
    Login or Signup to reply.
  2. Use promise chaining to make both calls in the same useEffect block, and avoid the need to save redundant data in the state:

    useEffect(() => {
      axios.get(`/lists/user/${thisUserID}`)
        .then((response) => {
          const { listName, _id } = response.data[0];
          setListNames(listName);
          setListID(_id); // remove if the listId is only use for the 2nd request
          
          return _id;
        })
        .then((id) => axios.get(`/listcontent/user/${id}`)) // make 2nd call when the id (list's id) is available 
        .then(({ data }) => {
          setListContent(data);
        })
        .catch((err) => {
          console.error(err);
        });
    }, []);
    

    You can also flatten the code, and make it more readable, using async/await:

    useEffect(() => {
      const callApis = async () => {
        try {
          const user = axios.get(`/lists/user/${thisUserID}`)
          const { listName, _id } = user.data[0];
          setListNames(listName);
          setListID(_id); // remove if the listId is only use for the 2nd request
    
          const list = await axios.get(`/listcontent/user/${id}`); // make 2nd call when the id (list's id) is available 
          setListContent(list.data);
        } catch(err) {
          console.error(err);
        }
      };
    
      callApis();
    }, []);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search