0

The store has a method called getState that will return the current state of the store.

What prevents code somewhere in my application from (accidentally) modifying the returned state from store?

Let's say i call this:

let state = store.getState();
state.someProperty = 'fun';

The implementation that i've found on getState on the store object simply returns the inner state object that gets overwritten with each new action.

const getState = () => state;

In between actions/new states what prevents code from modifying the state that will be read by another subscriber? In my above example, setting someProperty to 'fun' will persist inside the store on the state property, until overwritten.

While i'm obviously not supposed to modify the state, a simple mistake might bind the state to some component that (unknowingly) modifies its inputs - perhaps on a 2-way binding in an angular environment?

<app-some-component [user]="state"></app-some-component>

Shouldn't getState() be implemented as a clone of its state model?

P.S. This is not specifically related to Angular - which is why i didn't add the tag - to allow more people not used to Angular to answer the question.

Per Hornshøj-Schierbeck
  • 15,097
  • 21
  • 80
  • 101

1 Answers1

1

The answer is: nothing :)

The core Redux library itself technically doesn't actually care if state gets mutated or not. You could actually mutate in your reducers, or have other parts of your app get the state tree and mutate it, and the store itself wouldn't know or care.

However, mutation will break time-travel debugging, as well as make tests unreliable. Even more importantly, the React-Redux library assumes that you will handle your state immutably, and relies on shallow equality comparisons to see if the state has changed. (This is the reason why "Why isn't my component re-rendering?" is in the Redux FAQ. 99.9% of the time, it's due to accidental mutation.)

If you are concerned about mutation, you can use a library like Immutable.js instead of plain JS objects, or use one of the several tools for freezing your state in development to catch mutations.

markerikson
  • 63,178
  • 10
  • 141
  • 157
  • You're saying i either need to have a model that is an Immutable (from immutable.js or the like) or i need to freeze my state when testing/developing but not freeze in production? – Per Hornshøj-Schierbeck Feb 17 '17 at 08:34
  • As I said, there's nothing in Redux itself that _enforces_ immutability. Even if you write your reducer code carefully, or use an immutable update utility lib, technically any part of the code _could_ call `getState` and mutate the contents. If you want to guarantee that doesn't happen, you need to use something other than plain JS objects, or something that freezes plain objects to ensure the code isn't mutating anywhere. That said, the rest of the app certainly shouldn't be _trying_ to mutate the state anywhere, but it does happen accidentally at times. – markerikson Feb 17 '17 at 20:29
  • Just can't help thinking this is bad - prone to accidents - guess automated testing will be more important than ever... – Per Hornshøj-Schierbeck Feb 20 '17 at 07:52
  • Still kinda repeating myself here: technically, mutation is legal in Redux, it's just not usually something you want. If you want to prevent it, I've listed the approaches you can use. For example, the [DevTools#Linting](https://github.com/markerikson/redux-ecosystem-links/blob/master/devtools.md#linting) section of my Redux addons catalog lists the various "freeze-in-dev" tools that are available to help catch errors. – markerikson Feb 20 '17 at 17:05
  • But freezing in dev might not catch a mishandle of state in a corner of the app you're not currently developing - some edge case, once in production those bugs creep up... unless you're vigorously unit testing (which i know, you should ofcourse...) I know i could use immutablejs/etc - just adding complexity to what should be a simple model. But perhaps those bugs would still be there (just not as impactful/visible) had the state not been mutateable... perhaps i'm overthinking/complicating it - still pursuing the pattern atm :) – Per Hornshøj-Schierbeck Feb 21 '17 at 08:33
  • 1
    Honestly? Yeah, you are :) Yes, accidental mutation is a concern. But as I've listed, there's many ways to deal with that. The basic Redux pattern alone makes things simpler because all your "write" logic is moved to reducers, so all the _intentional_ changes are in one area. From there, only `mapState` functions and possibly action creators should be accessing the state, so that really narrows down any possible places that _could_ be doing mutation. There's no 100% guarantee, but between that and freezing/immutable libs, it shouldn't be a meaningful problem. – markerikson Feb 21 '17 at 16:37