Skip to content

Latest commit

 

History

History
173 lines (134 loc) · 6.96 KB

File metadata and controls

173 lines (134 loc) · 6.96 KB

Immutable

Git is a Persistent Data Structure with Directed Acyclic Graph. Persistent Bit-Partitioned Vector Trie.

You lose the convenience of setState since it rely on being able to mutate your state. Your only option is replaceState.

The Dao of Immutability: The true constant is change. Mutation hides change. Hidden change creates chaos. - Eric Elliott

Don't use Array.shift, use Array.slice instead for immutability.

Immutable data structure with structure sharing.


// Use map(), filter(), concat() for non-destructive array
// Use concat() instead of push()
let updatedPassengers = this.state.passengers.concat('mech');

// Use Object.assign for getting a new copy instead of mutating existing
// After the assignment, updatedTicket is an entirely different object than this.state.ticket
var updatedTicket = Object.assign({}, this.state.ticket, {flightNo: 'SQ112'});
this.setState({ticket: updatedTicket});

If you are using nested object, you are in trouble as neither Array's non-destructive methods nor Object.assign makes deep copies. Making a deep clone will be expensive on performance and even impossible to do in some cases. However, React provides a set of utility called Immutability Helpers that can help to update more complex and nested models.

Values and Objects

  • Values, Value Objects - Immutable. Number, Address
  • Objects, Entities - Mutable, with identity. User, Order

You Order has an id and can change over time. The items can changed, the amount can change.

The Address does not have an id and won't likely change over time. The value itself is the identity.

class Address
  include Virtus::ValueObject
  
  attribute :street, String
  attribute :zip, String
  attribute :city, String
end

Object.assign - Expensive Immutable Data Structure

Note: Neither the array's non-destructive methods nor Object.assign make deep copies.

Object.assign can be okay way to do immutability for small number of list items. But it is not performant for large lists.

 toggleActive: function(userId) {
    // State should never be mutated (changed) directly. You should
    // always make a copy of the state and replace the original
    // with the copy. In this case, we're replacing the whole state
    // which probably doesn't have the best performance for many
    // records, but it's good enough for this example. We'll talk
    // more about mutable and immutable state in the third article
    // on Redux.

    var newState = Object.assign({}, this.state)
    var user = _.find(newState.users, {id: userId});
    user.active = !user.active

    // Or
    var newUser = Object.assign({}, user, {active: !user.active});
    
    this.setState(newState)
  }
function getOlder(person) {
  return Object.assign({}, person, { age: person.age + 1 })

  // Or ES7 - Spread properties
  return {...person, age: person.age + 1}
}

// Using Babel
// Immutable
function updateUserScore(user, points) {
  return {
    ...user,
    points: user.points + points
  }
}

// Mutable
function updateUserScore(user, points) {
  user.points += points
}

// Or ES6 spread and deconstruct
function getOlder({ age, ...other }) {
  return { age: age + 1, ...other }
}
(defn get-older [person]
  (assoc person :age (+ 1 (:age person))))

Array

Let's say you have this structure:

this.state = {
  passengers: [
    'Simmon, Robert A.',
    'Taylor, Kat R.'
  ],
  
  ticket: {
    company: 'Delta',
    flightNo: 'SA0900',
    departure: {
      airport: 'LAS',
      time: '2016-08-12T14:41:10.000Z'
    }
  }
}

If you want to add more passengers, you likely use Array#push method. Since you are working with a reference, you have just mutated your array destructively. Non-destructive methods like map, filter and concat will give you a new copy instead.

// To add a new passenger
let updatedPassengers = this.state.passengers.concat('Mitchell')
this.setState({ passengers: updatedPassenger })

// To change flight number
let updatedTicket = Object.assign({}, this.state.ticket, { flightNo: '1010' })
this.setState({ ticket: updatedTicket })

Video