Doesn't copying a large state in redux reduce performance?

Viewed 1067

I understand that in Redux's reducers we don't change the state, we make a copy of the state, and then we change the copy.

But what happens if the state is very large. For example, maybe the state holds data we got from the server and can be several megabytes in size.

So if we make a copy of it each time in the reducer, wouldn't that slow the app?

Note: I looked at the redux documentation (https://redux.js.org/docs/faq/Performance.html) in regards to performance and it speaks about 'shallow copies' vs 'deep copies', and how shallow copies doesn't hamper performance as much.

Let's say I have an object of students that is 40mb in size. If I move these to a new state object, does that mean just a pointer gets modified so there's no performance impact?

2 Answers

The short answer: it depends.

Specifically, it depends on the kinds of operations that you are using in your reducers. If you find yourself frequently creating / modifying complex subtrees of your app's sate tree, you might want to look at libraries that efficiently handle immutability (see Immutable.js).

If you profile your application and find that you are needlessly modifying some parts of your sate's subtrees, you could take a look at redux-ignore, which allows you to ignore certain actions based on predicate functions.

With that said, most applications don't need either of the two libraries above as you will most likely only be modifying a small section of your state's tree as a response to an action. If you've split your root reducer into smaller reducers that handle specific parts of your tree (technique explained here), then you are most likely creating a few objects for every action, regardless of how many total objects exist in your state tree.

While it's true that your root reducer is returning a new object for every state change, you are not required to create a deep copy of your previous state for every state change. Most of the time, the object returned by your root reducer will reuse a majority of the objects that were in your previous state.

in your example of having a huge object containing large strings like so:

let tree = {

    student1: ..., // huge string
    student2: ... // enormous string
    ... // more huge strings
};

let newTree = Object.assign({}, tree);

Our newtree is actually created extremely quickly, as the strings in the object are passed by reference, so Object.assign's job is very easy: it just has to copy the existing references to the student strings into a new object that will serve as our application's updated state tree.

The same conclusion is true if our student properties were pointing to huge objects. Those objects would not be recreated when we create a new tree. Instead, the object references will be copied over to the new state tree.

In summary, as long as you are not making deep copies of your state tree for each action, your new state tree will reuse most of your old tree's properties, making the state update performant.

Ideally you're only copying the piece of state that needs to be modified, not an entire large, deeply-nested object. You can read through these links to see discussion points that may be relevant to your implementation/usage. Performance is unlikely to be a real concern if used as designed.

Redux Performance FAQ

Redux Performance Discussion

Reddit Discussion

Related