Now we know how to create an Immutable Map, we’ll take a look at how we can get data from it, and how to add and delete items from it, all without mutating it.

Note that the usual caveat applies: Immutable does not change a Map with any operation, so whenever you see phrases such as ‘delete an item from a Map’, the mutation occurs in a copy of the Map being operated on, which is returned from the appropriate function. The Map being operated on remains completely unchanged.

Getters

Get a value from a Map with get()


// Get a value from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers'
});

// Get captainAmerica
avengersMap.get('captainAmerica');


Get a default value from a Map if the key is not found

Ordinarily, if you try to get() the value of a key that does not exist from a Map, you’ll get the value undefined. However, Map.get() lets you provide a default that’s returned instead:


// Get a default value from a Map for a key that does not exist

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers'
});

// Get captainAmerica
avengersMap.get('blackWidow', 'Missing Avenger');


Get a value deeply embedded in a Map

You can walk down a deeply-nested Map’s object hierarchy by using an array of key names in the Map.getIn() function, with each key name belonging to a Map in the next level of the hierarchy.


// Get a value deeply embedded in a Map

// Note: we use Immutable.fromJS() to create our Map, as Map() itself 
// won't convert all the properties of a deeply nested object.
const avengers = Immutable.fromJS({
        hero1: {
            ironMan: {
              heroName: 'Iron Man'
            }
        }
    });


// Get ironMan's heroName
avengers.getIn(['hero1', 'ironMan', 'heroName'])

Get the value of the first key in a Map


// Get a default value from a Map for a key that does not exist

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

// Get Tony Stark
avengersMap.first();


Get the value of the last key in a Map


// Get a default value from a Map for a key that does not exist

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

// Get Natasha Romanov
avengersMap.last();


Determine if a key exists in a Map with has()


// Get a default value from a Map for a key that does not exist

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

// Does blackWidow exist?
avengersMap.has('blackWidow');

Determine if a key exists in a deeply nested Map with hasIn()


// Get a value deeply embedded in a Map

// Note: we use Immutable.fromJS() to create our Map, as Map() itself 
// won't convert all the properties of a deeply nested object.
const avengers = Immutable.fromJS({
        hero1: {
            ironMan: {
              heroName: 'Iron Man'
            }
        }
    });


// Does the key 'heroName' exist?
avengers.hasIn(['hero1', 'ironMan', 'heroName']);


Determine if a value exists in a Map with includes()


// Get a default value from a Map for a key that does not exist

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

// Does Natasha Romanov exist?
avengersMap.includes('Natasha Romanov');

Note: You can also use .contains() instead of includes() – it does exactly the same thing.

Get all the keys from a Maps with keys()

You can get all the keys from a Map using Map.keys(). However, the returned value is an ES6 iterable, which on its own, isn’t that useful:


// Get all the keys from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

avengersMap.keys();

Fortunately, you can access each item in an iterable using iterator.next(), or, more succinctly (and probably what you were hoping to get in the first place), convert the returned iterable to an array using the spread operator.

Here are examples of both options:

Using iterator.next()


// Get all the keys from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

const avengersKeys = avengersMap.keys();

// Each call to avengersKeys.next() will return the next key in avengersMap
// as a value in the next() function's returned object. Confused? This is
// just how iterables work in ES6. If you're looking to get an array of 
// keys, see the example with the ...spread operator below.
avengersKeys.next();

Using the …spread operator


// Get all the keys from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

const [...avengersKeys] = avengersMap.keys();

avengersKeys;


Get all the values from a Map with values()

Get all the values from a Map, returned as a JavaScript iterable. See the section on getting all the keys of a Map for how to access the values from the iterable.


// Get all the values from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

const [...avengersValues] = avengersMap.values();

avengersValues;


Get both keys and values from a Map with entries()

Get all the key/value pairs from a Map, returned as a JavaScript iterable. See the section on getting all the keys of a Map for how to access the values from the iterable.


// Get all the values from a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers',
   blackWidow: 'Natasha Romanov'
});

const [...avengersEntries] = avengersMap.entries();

avengersEntries

Setters

Add new key/value pair to a Map with set()


const updatedMap = oldMap.set(key, value)


// Add a new key/value to a Map

const avengersMap = Immutable.Map({
   ironMan: 'Tony Stark',
   captainAmerica: 'Steve Rogers'
});

const moreAvengers = avengersMap.set('blackWidow', 'Natasha Romanov');

// Output:
moreAvengers;

Note: if the key already exists, its value will be updated with the new value.


Add a new value to an existing key in a deeply nested Map with setIn()

const updatedMap = oldMap.setIn(keyPath, value)

where:

  • keyPath is an array of keys that is used to walk down the Map hierarchy
  • value is the new value want to give to the final key in keyPath

// Set a new value in a deeply-nested Map

const ironManMap = Immutable.fromJS({
  hero: {
    ironMan: {
      realName: 'Tony Stark',
      partner: 'Pepper Potts'
    }
  }
});

const updatedIronMan = ironManMap.setIn(['hero', 'ironMan', 'realName'], 'Anthony Stark'); 

// Output:
updatedIronMan;


Note that unlike Map.set(), which adds a new key/value pair to a Map, Map.setIn() replaces the value of an existing key. if you want to add a new key/value pair in a deeply nested Map, you’ll need Map.updateIn() or Map.mergeIn, both of which will be covered in another post.

Updaters

The difference between Map.set() and Map.update() is subtle. They both let you change the value of a key in a Map, butupdate() gives you more control over the update process by letting you provide your own function to manage the update.

There are three ways you can use it:

  • act on the whole Map
    const newMap = oldMap.update((oldMap) => { /* update oldMap */ })
  • act on a single key/value pair
    const newMap = oldMap.update(key, (value) => { /* update value */ })

  • act on a single key/value pair, and provide a default value if the key doesn’t exist
    const newMap = oldMap.update(key, 'defaultValue', (value) => { /* update value */ })

Act on the whole Map


// Act on the whole Map

const avengersMap = Immutable.Map({
  ironMan: 'Tony Stark',
  captainAmerica: 'Steve Rogers',
  blackWidow: 'Natasha Romanov'
});

const updatedAvengers = avengersMap.update((avengers) => {
  // avengers is a Map, so we need to return the value from set() to change
  // its values
  return avengers.set('ironMan', 'is Tony Stark');
});

// Output:
updatedAvengers


Act on a single key/value in a Map



// Act on a single key/value in a Map

const avengersMap = Immutable.Map({
  ironMan: 'Tony Stark',
  captainAmerica: 'Steve Rogers',
  blackWidow: 'Natasha Romanov'
});

const updatedAvengers = avengersMap.update('ironMan', (ironManValue) => {
  // ironManValue is a JavaScript type - no need for Immutable 
  // functions to modify it
  return ironManValue + ' is ironMan';
});

// Output:
updatedAvengers


Act on a single key/value, and provide a default value if the key doesn’t exist



// Act on a single value in a Map, with a default value if the
// key doesn't exist

const avengersMap = Immutable.Map({
  captainAmerica: 'Steve Rogers',
  blackWidow: 'Natasha Romanov'
});

const updatedAvengers = avengersMap.update('theHulk', 'Bruce Banner', (theHulkValue) => {
   return theHulkValue + ' Smash!';
});

// Output:
updatedAvengers

Deleters

Delete a key from a Map

const updatedMap = oldMap.delete(key)


// Delete a key from a Map

const ironManMap = Immutable.Map({
   ironMan: 'Tony Stark',
   partner: 'Pepper Potts'
});

const lonelyIronMan = ironManMap.delete('partner'); 

// Output:
lonelyIronMan;


Delete a key from a Deeply Nested Map

const updatedMap = oldMap.delete(key)


// Delete a key from a deeply-nested Map

const ironManMap = Immutable.fromJS({
  hero: {
    ironMan: {
      realName: 'Tony Stark',
      partner: 'Pepper Potts'
    }
  }
});

const lonelyIronMan = ironManMap.deleteIn(['hero', 'ironMan', 'partner']); 

// Output:
lonelyIronMan;


Delete all values from a Map with clear()

const clearedMap = oldMap.clear()


// Clear all values from a Map

const ironManMap = Immutable.fromJS({
  hero: {
    ironMan: {
      realName: 'Tony Stark',
      partner: 'Pepper Potts'
    }
  }
});

const emptyIronMan = ironManMap.clear(); 

// Output:
emptyIronMan;

Merging Maps

Now we’ve done all sorts of things to an individual Map, it’s time to see how we can merge two or more Maps together. Of course, this isn’t as easy as it sounds, with no less than six different ways of merging, depending on what you want to achieve.

So we’ll look at this in the next post in this series. Follow me on Twitter if you’re enjoying this series, and want to know when I post a new article.

There are no comments.

Leave a Reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>