(I know that setters are asynchronous, I need a solution for how to mutate a unified Map and guarantee all values in the Map are thread-safe.)
In our React app, instead of using individual state variables, we have a unified valueMap
ES6 Map that gathers all form values. It has a mutator called handleValueMapChange(key,value)
. The inputs are hooked up to that valueMap as e.g. value={props.valueMap.get('someField')}
.
// Definition
const [valueMap, setValueMap] = useState<Map<string, any>>(new Map());
// Mutator
const handleValueMapChange = (id: string, value: any) => {
setValueMap(new Map<string, any>(valueMap.set(id, value)));
}
On certain input, there is a point where multiple async fetches are called in quick succession, and they will call handleValueMapChange
to manually set some values into the form.
// Example of multiple async fetches that are called in quick succession to manually set into valueMap
const fetchXX = async () => {
const response = await get<any>('app/fetchXX');
if (response) {
props.handleValueMapChange('fieldXX', response);
}
};
What I’m finding is that some intermediate valueMap
entries get lost. The goal is to have all of these valueMap
fields correctly set eventually regardless of where they get set from. Suppose fetch1
sets handleValueMapChange('field1','abc')
and fetch2
sets handleValueMapChange('field2','def')
, where they’re both initially ''
. At the end field1
is blank (''
) in valueMap
and the intermediate setting of that value from fetch1
got lost.
So the ES6 Map isn’t synchronized. We chose the ES6 Map form approach to avoid having lots of individual variables, and also to make it easier to submit the form to the server as one variable instead of many. Are there any solutions to this?
4
This is the solution,
setValueMap(prevValueMap => {
const newValueMap = new Map(prevValueMap);
newValueMap.set(id, value);
return newValueMap;
});
The updater function => was used per this documentation