1

I have a React/Redux project where I'm using a Web Worker to calculate the next state when an action is dispatched, and then pass the new state directly to the store, like this:

let nextReducer = reducer => {
    return (state, action) => {
        if (action.type === 'WEBWORKER') {
            return action.payload;
        } else {
            return reducer(state, action);
        }
    };
};

let store = createStore(nextReducer(rootReducer));

The problem is that when I manually pass the new state to the redux store, the state now has a new reference, and reselect library cannot memoize correctly the state. This has as a result that the view is always rerendering at every state change.

The thing is that I always thought that the state always had a different reference (even without manually setting it), because the rule is that we should never mutate the original state object, but we have to always return a new one. So, why if I use my rootReducer as is, reselect works fine, but when setting it manually it doesn't?

Zosimas
  • 518
  • 4
  • 15
  • Does the web worker evaluate the entire application state or just a specific branch of it? – Andrea Carraro Jul 17 '18 at 10:01
  • The web worker just runs the same "reducer" function that runs at the "else" condition, with the "state" and "action" arguments that are passed to the web worker as data. It then posts the result back, as an action with type "WEBWORKER" and the new state as payload. – Zosimas Jul 17 '18 at 10:56

1 Answers1

2

react-redux's connected components and reselect rely on object reference equality to prevent unnecessary renders/recalculations.

When sending objects to web workers, the object is serialized, and later deserialized, so you end up with a clone of the object lacking any reference equality with the original object.

A quick solution might consist of using the serviceWorker to only evaluate the specific state branch (or value) you need to update.

Consider also that in very special cases, reselect can be configured to perform custom deep equality checks, and the same is true for react-redux connect's mapStateToProps configuration.

Since reference equality plays an important role in redux architecture, can be worth point out that JS identity operator (===) compares arrays, functions and objects by reference while compares numbers and strings (plus undefined, null, boolean) by value.

Andrea Carraro
  • 9,731
  • 5
  • 33
  • 57
  • I understand that, but, inside the "reducer" I'm using the `seamless-immutable` library that is supposed to return new instances of the **state** every time that is changing it. But I never had problem with state reference before adding web workers. – Zosimas Jul 17 '18 at 11:49
  • 1
    If an object inside a `seamless-immutable` structure stay untouched, the same object (reference equality) will be returned when `immutableStructure.nestedObject` is accessed – Andrea Carraro Jul 17 '18 at 11:56
  • Ok, that make sense. So any solution on how to prevent re-rendering? (except shouldComponentUpdate checks) – Zosimas Jul 17 '18 at 12:27