Shira Navama
Shira Navama

Reputation: 41

When using useState hook - Is there an importance to changing the setState functions call order?

I have a React functional component with two state variables (itemsData & itemsCollections). The variables are updated in the useEffect method. But after useEffect occur one of the state variables is null.

Upon switching the setStateFunctions (setItemsData & setItemsCollect) call order both arguments are inialized as expected.

How's that?

const MyComponent = ({itemsIds}) => {
   const [itemsData, setItemsData] = useState([]);
   const [itemsCollections, setItemsCollect] = useState({});

 useEffect(() => {
        fetchItemsData({ itemsIds }).then(({ items, itemCollect }) => {
             setItemsData(items);
             setItemsCollect(itemCollect);
        })
    }, [itemsIds]);
...
console.log('itemsData', itemsData) // the expected array
console.log('itemCollect', itemCollect) // empty objecy

State after useEffect: itemCollect = {}, itemsData = [{value:...},...]

Switching the order of the calls:

const MyComponent = ({itemsIds}) => {
   ...
 useEffect(() => {
        fetchItemsData({ itemsIds }).then(({ items, itemCollect }) => {
             setItemsCollect(itemCollect); // <--> switched rows
             setItemsData(items); // <--> switched rows

        })
    }, [itemsIds]);
...
console.log('itemsData', itemsData) // the expected array
console.log('itemCollect', itemCollect) // the expected object

State after useEffect: itemCollect = { someValue: ...} , itemsData = [{value:...},...]

Upvotes: 4

Views: 1685

Answers (1)

Aprillion
Aprillion

Reputation: 22340

There is a performance optimization called batching, which can change between React versions. When this optimization is applied, multiple setState calls will be batched together before the next render (and the order does not matter).

When not applied (e.g. inside a Promise as in your case, see Does React batch state update functions when using hooks?), then each state update will trigger a new render (and the order matters).

=> console.log('itemCollect', itemCollect) may log different data in each render.

If you need to force a single state update, then calling a single dispatch from useReducer might be the best option.

Upvotes: 2

Related Questions