Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Don't notify subscribers when after action state hasn't changed, add test #4627

Closed

Conversation

gentlee
Copy link

@gentlee gentlee commented Dec 1, 2023


name: Optimization of subscriptions
about: Performance

PR Type

Does this PR add a new feature, or fix a bug?

No.

Why should this PR be included?

Problem

Up to 50% of all dispatched actions in the apps that use redux-saga or redux-thunk could be ones that don't change the redux state but start some async logic.

Current implementation notifies subscribers for each such action even if state hasn't changed, causing all active selectors to be reevaluated.

In huge apps there can be hundreds of subscribed selectors and dozens of actions per second, so this leads to additional CPU usage for no good reason.

Solution

Don't notify subscribers when action did not change the state.

Can it break existing code?

As far as I can see, the only reason to subscribe to the store is to get the new state using store.getState(). There is no sense in subscribing to get the called action because there is no way to get the latest action called from subscription. So it should not break any existing code.

But I would vote for raising major version here.

Checklist

  • Have you added an explanation of what your changes do and why you'd like us to include them?
  • Is there an existing issue for this PR?
    No, as far as I know.
  • Have the files been linted and formatted?
  • Have the docs been updated to match the changes in the PR?
  • Have the tests been updated to match the changes in the PR?
  • Have you run the tests locally to confirm they pass?

@gentlee gentlee changed the title Don't notify subscribers when state after action hasn't changed, add test Don't notify subscribers when after action state hasn't changed, add test Dec 1, 2023
Copy link

codesandbox-ci bot commented Dec 1, 2023

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 32becea:

Sandbox Source
Vanilla Typescript Configuration

@gentlee gentlee force-pushed the alex/subscription-optimization branch from 5f8f589 to 32becea Compare December 1, 2023 18:53
@markerikson
Copy link
Contributor

markerikson commented Dec 1, 2023

Hi! I recognize your username from some recent discussions in the React-Redux repo.

This is actually an intentional design decision, and not something we will be changing:

However, you can implement this same logic as a Redux store enhancer, and add it to your own store in your app.

I'll also note that React-Redux should actually already be skipping all store subscription / selector checks when the root state has not changed. If it isn't, that seems like a bug and we should investigate that separately.

(I'll also note that RTK's autoBatchEnhancer already does something sort of similar - if it sees multiple actions tagged as "low priority" in a row, it delays notifying subscribers until a timer expires or it sees another "standard priority" action: https://redux-toolkit.js.org/api/autoBatchEnhancer . You could look at that for some inspiration, or try tagging saga actions as "low priority" to make use of that. It's already turned on by default in RTK 2.0.)

@markerikson markerikson closed this Dec 1, 2023
@gentlee
Copy link
Author

gentlee commented Dec 1, 2023

Hi @markerikson. I checked link you have sent, I totally agree with it and actually my change even follows to what it says:

but not that it always calls each subscriber for each action

Also, I've came exactly from react-redux after checking that it uses useSyncExternalStore for subscriptions and it does not skip such actions without changes.

And I tested it with my udpate - it stopped reevaluating selectors when state is not changed.

@gentlee
Copy link
Author

gentlee commented Dec 1, 2023

As for the layer where to fix this issue, it makes sense to me that it is better to remove the root cause of a problem which is here. I don't understand what lies beyond that design decision to notify subscribers when state hasn't changed considering that we don't pass state and action to the subscriber.

@markerikson
Copy link
Contributor

Hmm. It used to bail out. Maybe we lost something in the transition to useSyncExternalStore in v8.

I'm not questioning whether the change here makes a difference. I'm saying it's a piece of core behavior we're not going to alter, and that it can be overridden at the enhancer level.

@markerikson
Copy link
Contributor

Filed reduxjs/react-redux#2089 and I'll try to look at it soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants