React: Setting state to an es6 Map

React state should be immutable because React uses shallow compare to check for equality. When comparing scalar values (numbers, strings) it compares their values. When comparing objects, it does not compare their properties - only their references are compared (i.e. "do they point to same object ?").

ES6 Maps are not immutable and are optimized for mutability, that's why it's not recommended to use these in React as it is. React will not know whether map is updated or not.

var map1 = new Map();
var map2 = map1.set('b', 2); // mutate map
map1 === map2; // true because reference remains unchanged after mutation

You can use Maps if you want but you need to use some immutability helper e.g. Immutable.js. Following example is using immutable map

const { Map } = require('immutable');
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 2); // Set to same value
map1 === map2; // true
const map3 = map1.set('b', 4); // Set to different value
map1 === map3; // false

References:

https://github.com/reduxjs/redux/issues/1499#issuecomment-194002599

https://stackoverflow.com/a/36084891/2073920


If you don't want to use an immutable library you can create a new Map on change (this is a cheap shallow copy of the pointer to the map, the same as spreading an object):

const [someMap, setSomeMap] = useState(new Map());

And when you need to update it:

setSomeMap(new Map(someMap.set('someKey', 'a new value')));

The same concept applies to Redux:

case 'SomeAction':
  return {
    ...state,
    yourMap: new Map(state.yourMap.set('someKey', 'a new value'))
  }

With regards to serializability it's not a concern for local state. It's good practice to have a Redux store that is serializable though.

Can I put functions, promises, or other non-serializable items in my store state?

It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.

If you are okay with things like persistence and time-travel debugging potentially not working as intended, then you are totally welcome to put non-serializable items into your Redux store. Ultimately, it's your application, and how you implement it is up to you. As with many other things about Redux, just be sure you understand what tradeoffs are involved.

You can see that JSON.stringify unfortunately doesn't work on maps:

console.log(JSON.stringify(
  new Map([['key1', 'value1'], ['key2', 'value2']])
))

If you can get in between the serialization process you can use Array.from:

console.log(JSON.stringify(
  Array.from(new Map([['key1', 'value1'], ['key2', 'value2']]))
))