-
-
Notifications
You must be signed in to change notification settings - Fork 15.3k
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
nested reducer composition - performance question #634
Comments
They are re-rendered, but I don't see any performance hit if you're using React (since they're _diff_ed). I'm not sure how and why you'd have multiple |
To keep the performance... performant, it's up to you to use shouldComponentUpdate wisely in your components tree. The easiest way to do so is to use Immutable.js or something similar for your state - this way, to know if a particular sub-tree of the state has changed, shouldComponentUpdate can simply compare the reference. In other words, with immutability, you can use the PureRenderMixin freely in your components. |
No. If your function images(state, action) {
switch (action.type) {
case DO_SOMETHING_WITH_IMAGES:
return transformSomehow(state);
default:
return state; // <--------- note! returning same reference for any unknown action
}
} and if you're listening to Of course, if the view is listening to
It's not really related to Redux. Redux store will call every listener. However React Redux |
This is not correct, I think. If they are re-rendered, it means your nested state reducer returns a new object even when the state should not have changed. You need to write your reducers in such a way that they ignore unrelated actions.
Note that |
Thanks a'lot, thats what I'm looking for. So i'm good to go, I use reselect and return same ref if no change happened. |
@gaearon then maybe I didn't understand the docs well, or there is something else I'm missing.
This is what we're doing; currently in the app we're refactoring with Redux we have only one top-level component which is connected to the store, and a big enough tree of "dumb" components that descend from that root. If you connect only one top level component, which gets the whole state, won't it re-render every time there is any change in the state? That's why we used Immutable and PureRenderMixin in all the subcomponents; our idea is that the top level component will update, but then all the subcomponents that aren't affected by the change will actually not render. Doesn't the connect's aggressive shouldComponentUpdate only help if you have lots of small trees of components, each connected to the store, instead of one big tree? Or a few big trees? |
I think your question is if this ('connect' only at the top level) mapStateToProps(state) {
return {
users: state.entities.users,
images: state.entities.images,
};
}
@connect(...)
class TopLevelComponent extends ...
render() {
<UserComponent users={this.props.users} />
<ImageComponent images={this.props.images} />
} is equal in performance compared to ('connect' in every sub component) class TopLevelComponent extends ...
render() {
<UserComponent />
<ImageComponent />
} and mapStateToProps(state) {
return {
users: state.entities.users,
};
}
@connect(...)
class UserComponent extends ...
render() {
// do something with users
} and mapStateToProps(state) {
return {
images: state.entities.images,
};
}
@connect(...)
class ImageComponent extends ...
render() {
// do something with images
} I think it should be the same? |
Yes, you're right. Connecting only top-level component is by default slower than connecting components in the middle. The point is: use single
When either of these things happen, move The problem is with the docs, not with the implementation. We should explain more clearly about the tradeoffs of different strategies. Both “just one connect” and “connect every single component” aren't very good tradeoffs in my opinion, you should strive for the middle. |
@gaearon I get the point; for ourselves, we were thinking to use multiple "connect" at a later stage, when we'll have one or more unrelated component trees. Anyway, shouldn't using Immutable + PureRenderMixin improve the performance a lot in a situation like that? Most of the performance problems should probably come from the "inner loop" leaf components, for example when there is a big list of components inside another component, and I would expect shouldComponentUpdate() very quickly returning false for those to alleviate the problem a lot (but I never tested it yet). |
That's right. It's just not something we can enforce, and not really different from optimizing non-Redux React app, so I don't talk about it much—it's in React's documentation. |
@ms88privat of course the performance will be worse with only one connect, but, as @Gaeron says, there is also a tradeoff in using "many connects". Moreover, I can think about situations where I think that using "many connects" is actually impossible - ie when you have a tree of components that is deep and structurally dependent on the status/props of the root. |
@gaearon ok thanks that's what I wanted to be sure about. |
@gaearon I'm have an issue where I have a combineReducers like:
I'm getting all of their children components re-rendered. From what I understood:
it shouldn't re-rendered. |
This shouldn't be happening. Are you sure |
Sure. Basically every action dispatched from redux-form is changing the
I've also debugged this and I can confirm it returns the current state. Edit: Just to check if I'm correctly understanding this...
then if you click Add to Cart button, the code on the
shouldn't change the state and won't re-render, correct? |
It will cause a re-render because the |
@gaearon right, that in the shopping cart example but on my case it doesn't create a new value, just returns |
I can't help without a project reproducing the issue. |
I understand and sorry about that. Thanks. |
Hello,
my App is getting very large and so are my reducers. I split them into multiple files and structured them by nesting.
It looks something like this:
It is working fine, but my question is now, what happens when my "entities.users" change? Are the components which are listening for "entities.images" re-rendered too? (using connect@react-redux here)
So is the performance the same compared to not nesting (with the same reducer count) and besides the deeper object comparison which is negligible?
I'm not 100% sure how redux work here, I have to analyse the source code yet. But i wanted to share this example how to deep nest the reducers anyway.
Thanks,
The text was updated successfully, but these errors were encountered: