Description
React Easy State version: 6.3.0
Platform: browser
There is another subtle problem after calling an async function. Array mutation causes immediate re-rendering for each fundamental operation (set, get, etc). This will cause the list to re-render while it is in an internally inconsistent state.
import React from 'react';
import { store, view } from '@risingstack/react-easy-state';
async function longFunction() {}
const counterStore = store({
counters: []
});
counterStore.counters.push({value: 1});
counterStore.counters.push({value: 2});
counterStore.counters.push({value: 3});
export default view(() => {
const updateList = async () => {
await longFunction();
const c = counterStore.counters;
console.log("Before removing item")
c.splice(0, 1);
console.log("After removing item")
}
console.log("Current list:")
counterStore.counters.forEach((counter, index) =>
(console.log(`${index}: ${counter.value}`))
);
return (
<>
<button onClick={() => updateList()}>Update list</button>
<ul>
{counterStore.counters.map((counter, index) => (
<li key={index}>{counter.value}</li>
))}
</ul>
</>
);
});
Which generates the output:
Current list:
0: 1
1: 2
2: 3
Before removing item <- Button is clicked
Current list:
0: 2 <- Note that value 2 is duplicated
1: 2
2: 3
Current list:
0: 2
1: 3 <- Now value 3 is duplicated
2: 3
Current list:
0: 2 <- length is updated so list is correct again
1: 3
Current list:
0: 2
1: 3
After removing item
In this output we are seeing the internal implementation of splice as it copies down the array elements, and then finally updates the length
. This is a problem for React rendering because if the value
is being used as a key
value then the React display will become corrupted because of the duplicated keys. There will be a warning, but then you will also see duplicated items even after all of the renders have finished.
It seems that some kind of batching is required. There is batching around the event callback, but the async function closes the batch and subsequent changes are not batched.