Tools for immutable work

Most people reach for lodash for general-purpose JavaScript work. With the recent tides shifting towards functional programming, Ramda has become a popular option as well. I don't prefer to use them, let me show you why.

Accumulated bloat

Lodash is big

I love both lodash and Ramda, but they're a bit too bloated to use for web apps. A simple lodash.map weighs in at a whopping 24 kilobytes:

$ browserify -r lodash/map | uglifyjs -cm | wc -c
24895

Ramda is smaller

Ramda's R.map is slimmer, but still hefty at 7kb. This may not seem like much, but for a web application, every kilobyte matters.

$ browserify -r ramda/src/pluck | uglifyjs -cm | wc -c
7750

Loops

Using map

While JavaScript comes with Array.prototype.map, it's not very useful for objects. I don't appreciate that iterating through arrays are done differently from iterating through objects. Not only that, but iterating through Object.keys().map is one of the slower ways of looping through an object's keys.

// Iterating through arrays
array.map((val, key) => {
  /*...*/
})

// Iterating through objects
Object.keys(object).map(key => {
  let val = object[key]
  /*...*/
})

Optimization with object-loops

For this, I prefer object-loops. object-loops/map is only 1kb!

import map from 'object-loops/map'
map(array, (val, key) => {
  /*...*/
})
map(object, (val, key) => {
  /*...*/
})

Immutable set/get

Spread operator?

Setting deep keys is something that's needed in every Redux-powered app. While most Redux guides advice you to use the spread operator, it quickly gets unwieldy for deep structures.

// Plain mutable JS
state.albums[id] = album

// ESnext syntax
state = {
  ...state,
  albums: {
    ...state.albums,
    [id]: album
  }
}

Consider using 101

For this, 101 comes with 101/put and 101/pluck.

import set from '101/put'
import get from '101/pluck'

state = set(state, `albums.${id}`, album)
get(state, `albums.${id}`)

Deleting keys With 101

It comes with 101/omit as well as an immutable analogue for delete.

// Plain mutable JS
delete state.albums[id]

// Using 101
import del from '101/omit'
del(state, `albums.${id}`)

Recap

object-loops for iteration

object-loops is great for iteration.

// Iterating
import map from 'object-loops/map'

map(state.albums, (val, key) => {
  /*...*/
})

101 for many things

101 is great for setting/getting values from deep structures.

// Setting and getting
import set from '101/put'
import get from '101/pluck'
import del from '101/omit'

state = set(state, `albums.${id}`, album)
state = del(state, `albums.${id}`)
get(state, `albums.${id}`)