0

I am doing a form submission and I am fetching 2 API's. The first API gives me a token value which I then need as data for second API. I am putting the token in const[token, setToken] = useState();.

After receiving the token I use setToken to store the token. Now I want this token to be used for my next API call. But setToken is undefined in the second API call.

I'm calling both like this:

    axios
      .request(options)
      .then(function (response) {
        console.log(response.data.id);
        setToken(response.data.id)
      })
      .then(function(response) {
        saveCard();
      })
      .catch(function (error) {
        console.error(error);
      });

saveCard() is where I call my second API and it uses token which I had previously set. Before the token is set, it is calling saveCard() function. What can I do to call saveCard() function after the token is fully set.

incredible123
  • 103
  • 11
  • 1
    Does this answer your question? [How to use callback with useState hook in react](https://stackoverflow.com/questions/54954091/how-to-use-callback-with-usestate-hook-in-react) – Matt U Dec 09 '21 at 03:40
  • I will try the custom hook solution since useEffect will not work in my case. It is a form submission that requires the token. – incredible123 Dec 09 '21 at 03:44
  • 1
    I don't understand why you can't add a `useEffect` hook with a dependency on `token` to execute your second request – Phil Dec 09 '21 at 04:03
  • Sure I can execute it inside the ```useEffect``` with ```token``` as dependency but in my case it has to be done on a form submission. I will have to execute this second API call only when I have received certain values in the form along with the ```token``` then I have to submit the form. – incredible123 Dec 09 '21 at 04:12
  • Sorry, I didn't realize it was for a form submission. I'll retract my vote for the duplicate. Can you please edit your original question to indicate that this code is executed when submitting a form? – Matt U Dec 09 '21 at 04:35

1 Answers1

3

There are a few ways you could solve this, the easiest of which is probably to just pass the token from the first request down to the saveCard method -

axios
    .request(options)
    .then(function (response) {
        console.log(response.data.id);
        setToken(response.data.id)

        // This gets passed to the next function in the chain
        return response.data.id;
    })
    .then(function(token) {
        saveCard(token);
    })
    .catch(function (error) {
        console.error(error);
    });

And actually - you don't need to isolate the saveCard into a separate then callback -

axios
    .request(options)
    .then(function ({ data }) {
        const token = data.id;

        setToken(token);
        saveCard(token);
    })
    .catch(function (error) {
        console.error(error);
    });

But, if you really want to call the saveCard method using the token from the setState call, you're going to have to use a useEffect. You could do something like this:

// Presuming you have something that represents your form state
const [formData, setFormData] = useState({});

const [token, setToken] = useState("");
const [submitting, setSubmitting] = useState(false);

const handleSubmit = async () => {
    if (submitting) return;

    setSubmitting(true);

    try {
        const { data } = await axios.request(options);
        setToken(data.id);

    } catch (error) {
        console.error(error);
        setSubmitting(false);
    }
};

useEffect(() => {
    // We can only call 'save' if we are in "submitting" mode, 
    // and we have a token.
    if (!(submitting && token)) return;

    saveData();

    // You'd probably have to reset your token here too presuming
    // you need to fetch another one again when you save.
    setToken("");
    setSubmitting(false);

}, [submitting, token, formData]

As you can see it's a lot more awkward; so I guess you have to ask yourself, do you REALLY need the token as state? The cleanest solution would be to remove it entirely, and use async/await instead of promises:

try {
    // Get the token
    const { data } = await axios.request(options);
    const { id: token } = data;

    // Now use the token to submit the form - I'm presuming this is async too?
    await saveCard(token);

} catch (error) {
    console.error(error);
}
gerrod
  • 6,119
  • 6
  • 33
  • 45