nl pkr nl pkr - 2 months ago 19
React JSX Question

React Redux and Should Component Update Optimisation

Code:



Root Component

<Provider store={Store}>
<AppLayoutContainer>
{this.props.template}
</AppLayoutContainer>
</Provider>


AppLayoutContainer

....some code

return(
<div className={`AppLayoutContainer`}>
<Modal isOpen={isModalShown} .... />
<div>{children}</div>
</div>
)

....some code

function mapStateToProps(state) {
const { app } = state;
return {
isModalShown: app.isModalShown
}
}

export default connect(mapStateToProps)(AppLayoutContainer);





Problem:



Every time when Applayoutcontainer get
isModalShown
from Redux, My whole app is re-rendering and it's very bad. All I need is re-render only the Modal component and don't touch my
children
. I think it's possible with
ShouldComponentUpdate
method, but I really don't understand how to do it.

Any ideas ? I know that someone did it in his project and can advise some Best Practise for this. Thanks




UPDATE:



Read all answers and YES it's good solution to connect Modal with Store,
but what if

1) I want Modal component be pure (re usable) like or components ?

2) I need to use
isModalShown
in AppLayoutContainer ?

return(
<div className={`AppLayoutContainer`}>
<Modal isOpen={isModalShown} .... />
<div className={isModalShown ? 'blured' : null }>{children}</div>
</div>
)

DDS DDS
Answer

What you should do is not pass the isModal in the AppLayoutContainer's mapStateToProps function, but instead connect the Modal itself.

Any results from mapStateToProps that change will cause the connected component to rerender. In your case, your mapStateToProps connected to AppLayoutContainer returns the value of isModalShown which causes your AppLayoutContainer to rerender.

If you want to only rerender the Modal itself then just

export default connect(state => ({isOpen: state.app.isModalShown}))(Modal)

in your Modal file, or in a separate file if you like that better.

Also remove the isModalShown prop from the AppLayoutContainer because you don't need it and because leaving it there means the AppLayoutContainer will still rerender every time isModalShown changes (which is what you're trying to fix).

Update regarding question updates:

Issue 1:

You can have a pure Modal

export default function Modal(props) {
  return <span>Open={props.isOpen}</span>;
}

You can then make a specific Modal for a particular use:

import Modal from './modal';
import { connect } from 'react-redux';

export default const AppLayoutModal = connect(state => ({isOpen: state.app.isModalShown}))(Modal);

You can do this many times for all kinds of separate modals. In fact this is why is a good idea to use pure components.

Issue 2:

If you want to use isModalShown in AppLayoutContainer then you have some choices:

  • Just use it. React always renders an entire component. Because it's just one render method. It updates the DOM, if any, more fine-grained but if you want less stuff to render when something changes then it's up to you to make your render functions small. If you leave the component large then the whole thing will rerender.
  • You can chop down your components into smaller ones so they can be rendered separately. You can make a small component to only use isModalShown via connect directly so the large AppLayoutContainer doesn't change. Child components can and do update independently from their patent components.
Comments