Modifying an Immutable.js Map()

Share this video with your friends

Send Tweet

We will now look at five methods that modify an Immutable.Map(). I highly encourage you to visit the Immutable.js documentation where I am now. They are set, delete, clear, update and merge. These are used often, so let's get to know them well.

Nils
Nils
~ 9 years ago

i don't get why you wrapped every standard function if the purpose is to learn them by heart, especially since you changed the name of them.

Nils
Nils
~ 9 years ago

found and error.

it('should update todo', () => {

    const todo = new Todo("Todo 1", "I'm a todo!", false);
    
    let todos = Immutable.Map();
    
    todos = addTodo(todos, todo);
    
    todo.title = "New Title";
    
   // todos = todos.update(todo.id,todo => todo);

    expect(todos.get(todo.id).title).to.equal("New Title");
    
  }); 

https://jsbin.com/vugupiyico/1/edit?js,output Also passes, is it because the actual object saved in the map is not a Immutable object, just the map ?

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Hi Nils! They are wrapped in explicitly named functions to express their intent. addTodo() does what it says, which makes it easier for other programmers to read--this is a personal preference as I tend to separate concerns even in simple matters. I'm sorry if that was confusing.

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

You are right about the error! Since I didn't use an immutable structure inside the parent immutable object, mutating the object inside it resulted in a side effect. Here, I created a bin to illustrate: https://jsbin.com/xugefa/1/edit?js,output

Uncomment the line to make the test pass. Does that make sense?

JMBattista
JMBattista
~ 9 years ago

I'd find this more useful if we weren't wrapping the map methods inside other functions. We're getting more exposure to the helper function than the actual library methods.

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Hey JM! Sorry that wrapping the functions isn't as useful for you. I'll keep that in mind for future lessons. Thanks for the feedback!

Sandeep S Kumar
Sandeep S Kumar
~ 9 years ago

In todos.delete(todo.id, todo) second param todo is not required, is it?

compile
compile
~ 9 years ago

Hi get error in chrome console:

Uncaught SyntaxError: Unexpected token = It points to line 30 which is the following:

constructor(title="", text="", completed=false) {....................

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

You are correct, it is not required. Must have left in the second param on accident. Good catch!

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Hey compile,

Is this in JSBin with the ES6 flag switched on? If not, then you need to make sure ES6 is enabled through Babel or some other transpiler.

compile
compile
~ 9 years ago

Was running in local dev environment and had to setup Babel 6, etc to get passing tests. Done now.

Tobias
Tobias
~ 9 years ago

Annoyed with all the extra wrapping: there's a class and every API call wrapped in a function. That's just complicating

Case Taintor
Case Taintor
~ 9 years ago
function updateTodo(todos, todo) {
  return todos.update(todo.id, todo => todo);
}

This does not update the todo since todo => todo will always map the object to itself. The todo from the function definition is masked by the todo in the updater definition.

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Hi Case,

It will update the key in the Todos Map and sets the key to the new todo object. You are correct, it does not update the todo itself.

Kemal Tatar
Kemal Tatar
~ 9 years ago

Without use update function this test passes either

it('should update todo', () => {

const todo = new Todo("Todo 1", "I'm a todo!", false);

let todos = Immutable.Map();
todos = addTodo(todos, todo);

todo.title = "New Title";
  
//todos = updateTodo(todos, todo);
expect(todos.get(todo.id).title).to.equal("New Title");

});

So add method gets the reference of todo object. But i didn't get why should i use update method and how. What is the best practice of updating it?

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Hi Kemal,

A slight oversight on my part. todo.title = "New Title" should be a new Todo() with the same ID. Then the original todo won't be mutated, the test will fail unless the updateTodo method is used with the new Todo(). Make sense?

Kemal Tatar
Kemal Tatar
~ 9 years ago

it('should update todo', () => {

const todo = new Todo("Todo 1", "I'm a todo!", false);
let todoId = todo.getId();
console.log(todoId)


const newTodo = new Todo("Hey There","I'm a todo!",false);
newTodo.setId(todoId);


let todos = Immutable.Map();
todos = addTodo(todos, todo);


todos = updateTodo(todos, newTodo); 

expect(todos.get(todoId).title).to.equal("Hey There");

});

I tried this but it didn't worked either. Weird part is test passes with todos = addTodo(todos, newTodo); function.

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Here's a simpler example that should clarify how to update: https://jsbin.com/bewaku/edit?html,js,output

describe('Modifying an Immutable.js Map()', () => {
  
  it('should update todo', () => {

    const todoID = "random_string_dklsfj9023";
    const todo = new Todo("Todo 1", "I'm a todo!");
    
    let todos = Immutable.Map();
    todos = todos.set(todoID, todo);

    todos = todos.update(todoID, () => new Todo("New Title", "I'm a todo!")); 
    expect(todos.get(todoID).title).to.equal("New Title");
    
  });  
  
});
Kemal Tatar
Kemal Tatar
~ 9 years ago

But in documentation of immutable.js update example is like this :

update(key: K, updater: (value: V) => V): Map<K, V>

here in the updater function we are passing value as parameter but if we do this it does not working. Am i missing something?

This is from source of map update function :

https://github.com/facebook/immutable-js/blob/master/src/Map.js

function updateInDeepMap(existing, keyPathIter, notSetValue, updater) { var isNotSet = existing === NOT_SET; var step = keyPathIter.next(); if (step.done) { var existingValue = isNotSet ? notSetValue : existing; ////////////////////////////////////////////////////////////////////////////////////////////////////////////// var newValue = updater(existingValue); ///////////////////////////////////////////////////////////////////////////////////////////////////////////// return newValue === existingValue ? existing : newValue; } invariant( isNotSet || (existing && existing.set), 'invalid keyPath' ); var key = step.value; var nextExisting = isNotSet ? NOT_SET : existing.get(key, NOT_SET); var nextUpdated = updateInDeepMap( nextExisting, keyPathIter, notSetValue, updater ); return nextUpdated === nextExisting ? existing : nextUpdated === NOT_SET ? existing.remove(key) : (isNotSet ? emptyMap() : existing).set(key, nextUpdated); }

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Kemal, Not sure I understand. update() takes a function that return the updated value. That's all. What isn't working?

Kemal Tatar
Kemal Tatar
~ 9 years ago

update(key: K, updater: (value: V) => V): Map<K, V> Yes but accourding to documentation i should pass the value to updater function but if i do that function is not updating map. https://jsbin.com/ribihun/edit?html,js,output

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Ah, I see why you're confused. :) (newTodo) => newTodo is a function signature, so newTodo is the argument name, not the lexically scoped variable from above. I can see why you thought you were passing the variable to the closure, but you are just returning the original variable from the Map(). In my example, I return a completely new Todo, which is why it updates. Does that make sense?

David Moody
David Moody
~ 9 years ago

I love the wrapping of the immutable functions. this helps me to get an idea of how people use immutable in the wild Thanks do that dude :-)

J.S. Leonard
J.S. Leonard(instructor)
~ 9 years ago

Glad to hear it David!

David Moody
David Moody
~ 9 years ago

are there any advantages or disadvantages to having a Map of objects like you are doing here rather than a Map of Maps?

Seb
Seb
~ 9 years ago

I can see why some people find the wrapping of functions strange but it does mean you can look at all methods in one place...

When I look at the bin there still is a second parameter to the delete function, which isn't needed, as mentioned in another comment...

I really like the videos and that you are "typing live". Looking forward to the remainder of the course.

HK
HK
~ 7 years ago

very confusing...

Paweł Waszczyński
Paweł Waszczyński
~ 6 years ago

Very confusing. Just looking at updateTodo example with some many "bugs", it does not encourage to move forward with this course.