You’re missing out on ImmutableJS Records
Immutable Records are immutably beautiful! — Ahmad Bamieh
Records are super simple to use, yet they provide tremendous advantages over regular the Immutable Map
. This post will introduce you to records, what are they and how to start using them right after.
Record Properties
A Record
is like an immutable Map
, however, it has the following unique features that makes it special:
- You cannot add more keys to it once it has been constructed.
- You can define default values for new record instances.
- The properties of a Record Instance can be accessed like regular JS objects, and can be destructed as well.
- You can name a record, for better debugging and error handling.
- You can extend the Record, to provide derived data from within the record.
This post will discuss all the following properties, but first, lets create our first record!
Creating a record
The Record
method returns a constructor function in which new instances could be made out of it.
const LivingCreature = new Immutable.Record({
name: "Unknown",
age: 0,
species: “Human”,
});let fooBar = new LivingCreature({name: “Foo Bar”, age: 24});
In this code snippet, we’ve created a Record of Living Creatures, and made a new LivingCreature
instance of fooBar
. NOTICE that this instance has the default species of Human
.
Descriptive Name
Records accept a second parameter for a descriptive name that appears when converting a Record to a string or in any error messages.
const NamedRecord = new Immutable.Record({...}, "[[NAME HERE]]");
Retrieving Properties
Unlike other ImmutableJS objects, records can be accessed like normal JS objects.
const {name, species} = fooBarfooBar.name // Foo Bar
fooBar["species"] // Human
Replacing Values
To replace fooBar
living creature with another creature, simply *swap records*.
fooBar = new LivingCreature({name: “Foo Bar Junior”, age: 8, species: “Half Blood”});
Updating Values
Using records, we can update multiple values at once using merge, in additional to using set
to update a single value.
fooBar.set('age', 20);
// or
fooBar.merge({
age: 25,
species: 12,
})
Adding new keys
The record throws an error if you attempt to add non-initialized keys on it. The following examples will throw an error:
const newFooBar = new LivingCreature({status: “its complicated”});const mergeFooBar = fooBar.merge({status: “its complicated”});
Removing Keys
Records always have a value for the keys they define. Removing a key from a record simply resets it to the default value for that key.
const newFooBar = fooBar.remove('name');
console.log(newFooBar.name) // → "Unknown"
Derived Values
One of the most powerful features that I personally love about records is their ability to derive data from within the record itself.
For example, lets say that we have a “Cart” of two items, and their sum
. In normal cases, every time we update an item value, we have to update the sum as well. Soon you will feel that this is not the best practice;
Records come to the rescue!
class Cart extends Immutable.Record({ itemA: 1, itemB: 2 }) {
get sum() {
return this.itemA + this.itemB;
}
}var myCart = new Cart()
myCart.sum // 3
Now we can update any value, and since the sum is derived from the record properties, there is no need to worry about it, or updating it manually.
const updatedCart = myCart.set('itemA', 5)
updatedCart.sum // 7
Conclusion
Records provide an amazing advantage of allowing your immutable objects to be treated like normal objects, by having standard accessors and object de-structuring, hence any library or component that does not mutate objects will welcome the records like one of their own!
Additionally, since record keys must be specified when the record is created, reading the record will clarify its use and self-document its purpose. It also enforces a more strict code style since you cannot add any more keys to the record.
After using record, I am left with astonishment why its very little talked about and why its not the standard rather than the Map
Immutable.
Thanks for reading! Follow me on medium Ahmad Bamieh Twitter @AhmadBamieh