Dealing with ((Im)mutable) Data
Emanuele Tonello
Lead Dev @ Flightsuit
It started so simple
this.setState({
toggle: !this.state.toggle
});
this.setState({
firstName: evt.target.value
});
this.setState({
redirect: "/another/route"
});
Now we here
this.setState({
first: {
second: {
fourth: {
field: "newValue"
}
}
}
});
let newState = this.state;
newState.first.second.fourth.field = "newValue"
this.setState(newState);
let newState = this.state;
newState.first.third.array[index] = 4
this.setState(newState);
this.state = {
first: {
second: {
fourth: {
field: ""
}
},
third: {
toggle: false,
array: [1, 2, 3]
}
}
};
What is the actual problem? *
"You have no way of determining which data has changed since the previous copy has been overwritten."
* more like one of the problems
[cit. React Docs]
also...
- deep copies and deep equals are expensive and sometimes impossible
- hard to wrap your head around
What this talk is not about
- not talking about data structures
- immutable-js
- not much about performance (maybe if we have time)
if you want to dig deeper into Immutability in React,
you can check this link: https://github.com/markerikson/react-redux-links/blob/master/immutable-data.md
immutability-helper to the rescue
previously 'react-addons-update'
kolodny/immutability-helper
(in line to be deprecated)
Meet your new friend
import update from 'immutability-helper';
const newData = update(myData, {
x: {y: {z: {$set: 7}}},
a: {b: {$push: [9]}}
});
// in React...
const newState = update(this.state, {
x: {y: {z: {$set: 7}}},
a: {b: {$push: [9]}}
});
this.setState(newState);
Pre-built commands
- $push: array
- $unshift: array
- $splice: array of arrays
- $set: any > replace the target entirely.
- $toggle: array of strings > toggles a list of boolean fields.
- $unset: array of strings > remove the list of keys in array.
- $merge: object > merge the keys of the object with the target.
- $apply: function > updates the current value with the new returned value from the function.
- $add: array of objects > add a value to a Map or Set.
- $remove: array of strings > remove the list of keys from a Map or Set.
Some examples
const newState = update(this.state, {
domains: {
$push: [response.data.domain]
},
$merge: {
newDomain: '',
openAddDomain: false,
isSubmitting: false
}
});
const newState = update(this.state, {
projects: {
[index]: {
$toggle: ["edit"]
}
}
});
const newState = update(this.state, {
selectedValues: {
$splice: [
[
this.state.selectedValues.length - 1,
0, {
from: null,
to: null,
depart: null
}
]
]
}
});
A bit beyond...
import update, {
extend
} from 'immutability-helper';
extend('$autoArray', function(value, object) {
return object ?
update(object, value) :
update([], value);
});
var state = {}
var state2 = update(state, {
foo: {
$autoArray: {
$push: ['x', 'y', 'z']
}
}
});
// var state2 = {
// foo: ['x', 'y', 'z']
// };
That's all folks!
@emanueletonello
emanuelet
Normalizing data with immutability-helper
By Emanuele Tonello
Normalizing data with immutability-helper
- 544