简体   繁体   中英

State not updating within a promised fetch (react)

I have a form with which i am sending data to my api. The data is used to create backend admin accounts and also create post entries. I need to post the data in a certain order to get some dynamic fields from the admin account to the post. For example:

  1. create the admin account to make an id field
  2. use the id field and apply to the post to create a unique link between admin account and post

Everything works apart from one state update that i'm trying to do after fetching the freshly created account:

// dont know what the ID will be as its dynamic

const [theID, setTheID] = useState('');

//Send the data to firstly create the admin account (works fine)

fetch('example.com/api/cockpit/saveUser', {
        method: 'post',
        headers: { 
            'Content-Type': 'application/json',
            'Cockpit-Token': process.env.REACT_APP_API_KEY
            },
        body: JSON.stringify({
            user: {
                user: firstname.toLowerCase()+surname.toLowerCase(),
                name: firstname,
                email: email,
                password: password,
                group: 'consumers',
            }
        })
    })
    .then(user => user.json())

    // make next fetch a chain of the promise
    // fetch all accounts but filter by email so will only return the right one

    .then(()=>{
        return fetch(`example.com/api/cockpit/listUsers&filter[email]=${email}`,{
            method: 'post',
            headers: {
                'Content-Type': 'application/json',
                'Cockpit-Token': process.env.REACT_APP_API_KEY
            }
        })
    })
    .then((res) => {
        return res.json();
    })
    .then((res)=>{
        // the console log works fine
        console.log(res[0]._id);
        // the state returns undefined
        setTheID(res[0]._id);
    })
    .catch((err)=>{
        console.error(err);
    })

    //Then last fetch to make the post entry works fine ...
      .then(()=>{
        return fetch('example.com/api/collections/save/consumers', {
            method: 'post',
            headers: {
                 'Content-Type': 'application/json',
                 'Accept': 'application/json',
                 'Cockpit-Token': process.env.REACT_APP_API_KEY,
            },
            body: JSON.stringify({
                data: {
                    firstname: firstname,
                    surname: surname,
                    password: password,
                    email: email,
                    project_name: projectName,
                    project_template: tmp,
                    // expected to get the dynamic ID front the state
                    ass_consumer: theID,
                    slug: projectName.toLowerCase().replace(' ','') + '-rr',
                    username: firstname.toLowerCase()+surname.toLowerCase()
                }
            })
        })
    })
    .then(user => user.json())
    .then((user)=>{
        setnewPage(user._id);
    })

I've checked the console which shows up fine after fetching. All my other state changes are bound to the form inputs but i've never had this problem with updating state in a fetch before.

I've also tried creating a function that takes the email as an argument then returns the state change but no luck with that either.

Appreciate any help!

(using cockpit as my api)

EDIT

This is what the console log returns: (i just need the _id)

{
 user: "johndoe", 
 name: "john", 
 email: "john.doe@example.com", 
 active: true, 
 group: "consumers", 
 _created: 1627039008,
 _id: "60faa5203365618a38000035",
 _modified: 1627039008,
}

You are most likely reading the state within the same operation ("too quickly"), so the state changes will not be reflected yet because the process to update React state is asynchronous.

You have 2 options to always get the most up to date state value:

  • Either use a reference to the state (check out this package )

  • Or use an "ugly" work-around taking the value from setState like this:

     const [id, setId] = useState("") setId("test") console.log(id) // "" // do this to get the up to date value, as the value // in setState is always the most up to date one let idVal setId(current => { idVal = current return current }) console.log(idVal) // "test"

So in your specific example, try this:

    //Then last fetch to make the post entry works fine ...
  .then(()=>{
    let customerID
    setTheID(current => {
      customerID = current
      return current
    })
    return fetch('example.com/api/collections/save/consumers', {
        method: 'post',
        headers: {
             'Content-Type': 'application/json',
             'Accept': 'application/json',
             'Cockpit-Token': process.env.REACT_APP_API_KEY,
        },
        body: JSON.stringify({
      
            data: {
                [...]
                // use the customerID variable, not the state variable
                ass_consumer: customerID,
               [...]
            }
        })
    })
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM