简体   繁体   中英

React Hooks useEffect won't use the correct state

<Button
    onClick={() => {
        console.log('addedNodes', addedNodes)
        let credentials = //something...
        let nodes = [...addedNodes]
        console.log(addedNodes)
        setCurrentForm(
            {
                ...currentForm,
                credentials: credentials,
                nodes: [...addedNodes],
            }
        )
    }}
</Button>

I have a button that updates the currentForm state using another state addedNodes . Whenever the currentForm gets updated, I console.log the currentForm using useEffect .

useEffect(() => {
        console.log('currentForm ,,,,,, ', currentForm)
        console.log('addedNodes ,,,,,, ', addedNodes)
    }, [currentForm]);

This prints out the CORRECT updated state.

However, when I try to add an API request using that state, it goes back to the state before it got updated.

For example, when I update my useEffect to

useEffect(() => {
        console.log('currentForm,,,,,, ', currentForm)
        console.log('addedNodes ,,,,,, ', addedNodes)
        console.log('RUNNING POST')
        setLoadingStatus('loading')

        let body = {
            form: currentForm,
        }

        intializeForms()
        let options = {
            headers: header,
            method: 'post',
            mode: 'cors',
            body: JSON.stringify(body),
        }
        console.log('options.body', options.body)

        const urls = ['...'];
        const fetchJson = url => fetch(url, options).then(res => res.json());
        Promise.all(urls.map(fetchJson))
            .then(([result]) => {
               ...
            })
            .catch(err => {
                setLoadingStatus('none')
                console.log(err)
            });

    }, [currentForm]);

The console.log('options.body', options.body) prints out the old currentForm .

This is very weird to be because console.log(currentForm) prints the expected state, but when I actually use it for an API call, it goes back to the original form.

I assume that it is because this useEffect gets called everytime the state gets updated, but not really sure.

Any help, please?

Problematic code fragment

 let body = { form: currentForm, } intializeForms() // later bad body.form content

form gets a reference to currentFrom object then currentFrom is overwritten in intializeForms() ... this way JSON.stringify(body) operates on bad data.

Why Kaca992's solution didn't worked?

 let body = { form: {...currentForm}, }

It should create a fresh object from currentForm ' element/properties.
Probably it worked for some part of currentForm , fe for nodes as they was properly (in immutable way - by new instance) assigned/passed:

 nodes: [...addedNodes],

Probably other currentForm elements are a copies of always the same object references , mutated on changes, not replaced with new instances.

Solution:

In this case it's enough to call intializeForms() just after currentForm "consuming" (stringify) - let options = block.

Other good place for form reset ( intializeForms() call) can be Promise.all(... resolving function ( .then part).

What does initializeForms do? If currentForms is a reference type maybe you reset the value? Try setting the body like this:

    let body = {
        form: {...currentForm},
    }

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