Set multiple variables at the same time in React

After React Hooks were introduced, the second parameter of setState (callback) was removed.

So, how can be you sure that a variable is updated? You need to use the useEffect Hook.

Ok, but what happens if you update multiple variables at the same time? Let's see.

The problem

In React, you can't guarantee that state updates are executed in order.

For instance:

jsx
import React, { useEffect, useState } from 'react';

const App = () => {

    const [caret, setCaret] = useState(null);
    const [text, setText]   = useState('');

    useEffect(() => {

        // You don't know if caret or text triggered useEffect
        // Was caret first? Or maybe text? 🧐 

    }, [caret, text]);

    const handleTab = (e) => {

        if(e.key === 'Tab'){

            setCaret(e.target.selectionStart);
            setText(e.target.value);

        }

    }

    return(
        <textarea
            onChange  = {(e) => setText(e.target.value)}
            onKeyDown = {handleTab}
            value     = {text}
        />
    )

}

export default App;

The solution

To guarantee that all the variables have been updated, you can set a variable with multiple parameters:

jsx
import React, { useEffect, useState } from 'react';

const App = () => {

    const [input, setInput] = useState({text: '', caret: null});

    useEffect(() => {

        // At this point, input variable (with both props text and caret) is updated

    }, [input]);

    const handleTab = (e) => {

        if(e.key === 'Tab'){

            setInput({
                text: e.target.value, 
                caret: e.target.selectionStart
            });

        }

    }

    return(
        <textarea
            onChange  = {(e) => setInput({text: e.target.value})}
            onKeyDown = {handleTab}
            value     = {input.text}
        />
    )

}

export default App;

Hi, I'm Erik, an engineer from Barcelona. If you like the post or have any comments, say hi.