The ability to reply to discussions is limited to PRO members. Want to join in the discussion? Click here to subscribe now.

Modifying an Immutable.js Map()

Modifying an Immutable.js Map()

5:22
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.
Watch this lesson now
Avatar
egghead.io

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.

Avatar
Nils

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.

Avatar
Nils

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 ?

Avatar
J.S.

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.

In reply to Nils
Avatar
J.S.

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?

In reply to Nils
Avatar
JMBattista

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.

Avatar
J.S.

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!

In reply to JMBattista
Avatar
Sandeep

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

Avatar
compile

Hi
get error in chrome console:

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

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

Avatar
J.S.

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

In reply to Sandeep
Avatar
J.S.

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.

In reply to compile
Avatar
compile

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

In reply to J.S.
Avatar
Tobias

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

Avatar
Case Taintor
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.

Avatar
J.S.

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.

In reply to Case Taintor
Avatar
Kemal

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?

Avatar
J.S.

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?

In reply to Kemal
Avatar
Kemal

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.

In reply to J.S.
Avatar
J.S.

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");

  });  

});
In reply to Kemal
Avatar
Kemal

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

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

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 === NOTSET;
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, NOTSET);
var nextUpdated = updateInDeepMap(
nextExisting,
keyPathIter,
notSetValue,
updater
);
return nextUpdated === nextExisting ? existing :
nextUpdated === NOT
SET ? existing.remove(key) :
(isNotSet ? emptyMap() : existing).set(key, nextUpdated);
}

In reply to J.S.
HEY, QUICK QUESTION!
Joel's Head
Why are we asking?