Zied Hamdi
Zied Hamdi

Reputation: 2662

state (from useState) using old value on a callback

I have a form with a file upload component that calls a props.onFileAdded callback when the upload ends.

axios.post(UPLOAD_URL, data, config)
        .then(function (res) {
            const {data} = res

            if (props.onFileAdded)
                props.onFileAdded(props.index, data)
        })
        .catch(function (err) {
            console.log(err)
        })

My issue is that my indexList state is reset when that callback is executed (onFileAdded is passed as the onFileAdded property):

const [indexList, setIndexList] = useState()
//... 
function addItem() {
    logger.debug("indexList was: ", ": ", indexList?.length, ":", indexList)
    const newIndexList = indexList == null ? [] : [...indexList]
    newIndexList.push(newIndexList.length)
    logger.debug("indexList became: ", newIndexList.length, ": ", newIndexList)
    setIndexList(newIndexList)
}

function onFileAdded(index, uploadedFile) {
    logger.debug("onFileAdded called")
    addItem()
}

To double check my problem I added in the parent component a button

    <Button onClick={addItem}>Add Item</Button>

And when I click that button, my state is updated as expected, but when I upload a file it is reset:

_app.js?ts=1625147479051:16572 indexList was:  :   : 
_app.js?ts=1625147479051:16572 indexList became:  1 :  0
_app.js?ts=1625147479051:16572 Rendering with index list:  0
_app.js?ts=1625147479051:16572 indexList was:  :  1 : 0
_app.js?ts=1625147479051:16572 indexList became:  2 :  0,1
_app.js?ts=1625147479051:16572 Rendering with index list:  0,1
_app.js?ts=1625147479051:16572 indexList was:  :  2 : 0,1
_app.js?ts=1625147479051:16572 indexList became:  3 :  0,1,2
_app.js?ts=1625147479051:16572 Rendering with index list:  0,1,2
_app.js?ts=1625147479051:16572 starting to upload
_app.js?ts=1625147479051:16572 file load finished
_app.js?ts=1625147479051:16572 onFileAdded called
_app.js?ts=1625147479051:16572 indexList was:  :   : 
_app.js?ts=1625147479051:16572 indexList became:  1 :  0
_app.js?ts=1625147479051:16572 Rendering with index list:  0

I found an answer here, but I can't figure out what to do onChange is resetting state - useState

Thanks for your help!

Upvotes: 3

Views: 5219

Answers (1)

Hassan Naqvi
Hassan Naqvi

Reputation: 1061

It is probably because the addItem() function has an old reference to your indexList

From the react docs:

If the new state is computed using the previous state, you can pass a function to setState. The function will receive the previous value, and return an updated value.

Try changing your addItem function to this:

function addItem() {
  setIndexList((oldIndexList) => {
    logger.debug("indexList was: ", ": ", oldIndexList?.length, ":", oldIndexList)
    const newIndexList = oldIndexList == null ? [] : [...indexList]
    newIndexList.push(newIndexList.length)
    logger.debug("indexList became: ", newIndexList.length, ": ", newIndexList)
    return newIndexList;
  })
}

Upvotes: 4

Related Questions