Skip to content

Instantly share code, notes, and snippets.

@anthony-dandrea
Last active June 2, 2016 04:18
Show Gist options
  • Save anthony-dandrea/74a3906d6dab9b8ce4666aa2e5961526 to your computer and use it in GitHub Desktop.
Save anthony-dandrea/74a3906d6dab9b8ce4666aa2e5961526 to your computer and use it in GitHub Desktop.
Write up of my immutable adventures

What is Redux?

A single state tree so React components can "talk" to each other. For example we click an "add to cart" button and want to +1 to the number in the header for cart items. The flow for changes in the tree go like so:

Components listening to click -> onclick redux action dispatches event -> reducer see's dispatch and if it corresponds to that event it will update state -> Components get new state passed down via props

^ If you're a react noob and it doesn't make much sense. Don't trip too hard because we're not talking about how redux works as much as immutablility.

What does immutable mean?

Instead of changing shit. Return a copy of the exact same shit with your changes.

Why do we GAF?

With complex apps there could be multiple changes to the state happening simultaneously. Shit will break and be hard to track down and fix. https://twitter.com/teozaurus/status/518071391959388160

WTF does this look like doe?

When making state changes instead of doing something like:

return state.isLoading = true;

which changes the property on state. ^Bad, don't fucking do that. Seriously. You need to do something like:

return {...state, isLoading: true}; //sexy
// or same shit different syntax
return Object.assign({}, state, {isLoading: true}); //maybe if drunk

^that's ES6 and creates a completely new object that copies the state and changes the value. That above is immutable.

Oh, neato that's easy!

Yea, it could be. Until you start making some super deep updates.

But WTF is a deep change Papa Tonez? I'm of the opinion that if you're doing something with a deep change there's probably a good chance you're doing something wrong but there are some cases where it's unavoidable. For example:

newState = {...state};
newState.toDisplay[selectedFacetGroupIndex].isSelected = newState.toDisplay[selectedFacetGroupIndex].isSelected ? false : 'selected';
return newState;

^That is bad and mutates the state. You may be wondering how because I just showed off that super sexy ... spread operator that creates a new object. Well it does but for deep values it actually just references the original object. Yea, super unintuitive, I know. Turns out making deep clone's is actually pretty expensive performance wise so it only does a shallow copy.

Well shit, I need to do a deep change.

You have a few options about how to go about this, I'm going to include the shitty ones you should never do for shits & gigs.

  1. Fuck it, lets just do a bunch of shallow copies: Don't. I tried it. I actually succeeded. It was some of the fugliest code I've ever seen and any maintenance changes would be a nightmare. And I doubt it's even performant. I was actually going to code an example of this but I got mad.

  2. Fuck it, just do a deep copy. Lodash and other libs have cloneDeep functions. Shit is expensive. Especially if you need to do this for every state change.

  3. Hey I checked da googlez and there's Immtuable.js! Yea, this library is pretty sick. It takes some time to wrap your head around but instead of objects and arrays you have maps and lists. The methods on maps and lists return new maps or lists instead of mutating the original. This isn't all rainbows and sunshine however. This library has a completely different API for getting values.

// set value
return state.updateIn(['toDisplay', selectedFacetGroupIndex, 'isSelected'], (v) => v ? false: 'selected');
// can't use dot notation no mo'
state.getIn(['toDisplay', selectedFacetGroupIndex, 'isSelected']);

Why does this matter? If you make all your components with this in mind it's not so bad. If you didn't and you're converting stuff over it can be a real pain.

  1. I just want something easy. There's seamless-immutable. It has essentially the same API for setting values as Facebook's Immtuable library. But this one you can retrieve values using typical dot notation. Fahk yaaaa.
// set value
return state.updateIn(['toDisplay', selectedFacetGroupIndex, 'isSelected'], (v) => v ? false: 'selected');
// easy AF
state.toDisplay[selectedFacetGroupIndex].isSelected;

Any good battle stories?

You bet! My personal favorite is the object comparison. People did this and I'm pretty sure thought it did something that it didn't:

if (nextProps.filters !== this.props.filters) {
  updateShit();
}

^ that actually checks not only values of the two objects but if they are the "same" object:

{} === {}
// false
var foo = {}
foo === foo
// true

I ended up having to pull some shit like:

// JSON.stringify() is surprisingly performant compared to other deep comparison functions
if (JSON.stringify(nextProps.filters) !== JSON.stringify(this.props.filters)) {
  updateShit();
}

Another battle of mine was when I found people mutating the state in components instead of using a redux action/reducer. I didn't even know you could fucking do this. I'm actually kind of confused why they allow it.

//In there component there would be shit like this
this.props.product.isLoading = true;

Should have done something like this with a action/reducer

// component
this.props.loadProduct(true);
// action
function loadProduct(bool) {
  return {
    type: 'LOAD_PRODUCT',
    bool: true
  };
}
// reducer
function loadProductReducer(state = false, action) {
  const { type, bool } = action;
  switch (type) {
    case 'LOAD_PRODUCT':
      return bool;
  default:
    return state;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment