I am using redux with react and typescript for my application. I am working with many items used at different places of my app. My state looks like this:
{
items: {42: {}, 53: {}, ... }, //A large dictionary of items
itemPage1: {
itemsId: [ 42, 34, 4 ],
...
},
itemPage2: { ...
},
...
}
The user can modify some attributes of the items
dispatching some actions. When this happen I need to redraw the components that have been modified in each pages. The issue is that my items are quite big and I cant afford to redraw all of them at each small modification. I was wondering is this approach would work:
<ItemPage1>
which connects to the store to get all of the states stored in the tree under itemPage1
e.g. the list of items id: itemsId
.<ItemPage1>
, I loop over the itemsId
property to generate multiple FilterItem
components: itemsId.map( itemId => return <FilterItem id=itemId>);
Finally each Item
is connected using ownProps
to get the correct part of the state:
const mapStateToItemProps = (state, ownProps) => {
return {
item: state.items[ownProps.id],
}
}
const mapDispatchToItemProps = (dispatch, ownProps) => {
return null;
}
const FilterItem = connect(
mapStateToItemProps,
mapDispatchToItemProps
)(Item)
Can you confirm or refute that if I update the item of id 42, then only this item is going to be re-rendered ?
Imagine if you have a lot of sub components. An update to state or props would render each individual sub component. Depending on that sub component, that can be pretty bad news. The shouldComponentUpdate() lifecycle is great to avoid multiple renders.
Preventing Re-Renders: The Old Way To prevent the render method from being called, set the return to false, which cancels the render. This method gets called before the component gets rendered. Sometimes you may want to prevent re-render even if a component's state or prop has changed.
Any time any piece of the Redux state is updated, our Component will re-render, regardless of whether the store update was related to our component or not.
In order for props to change, they need to be updated by the parent component. This means the parent would have to re-render, which will trigger re-render of the child component regardless of its props.
When rendering big list you need to take into considerations few things :
Basically, what you want to avoid is a complete re-render of your list (or your page) when the user edits one single row. This can be achieved exactly how you did it, i.e : by passing to the list container only the ids of items that need to be rendered, and to map over these ids to connect
each component by using ownProps
. If you have a dump <Item/>
component, your <ItemPage/>
component will create connected connect(<Item/>)
component.
This is going to work, if your put a console.log('item rendered')
in your <Item/>
component class you will notice that there is only one call.
BUT (and it's a big but), what is not obvious when working with react-redux
is that all connected components that depends on their ownProps
will always rerender if any part of the state change. In your case, even if the <Item/>
components will not re-render, their wrapped component connect(Item)
will ! If you have few dozens of items, you might encounter some latency if actions need to be dispatched quickly (for example when typing in an input). How to avoid that ? Use a factory function to use ownProps
as the initial props :
const mapStateToItemProps = (_, initialProps) => (state) => {
return {
item: state.items[initialProps.id], // we're not relying on the second parameters "ownProps" here, so the wrapper component will not rerender
}
}
const mapDispatchToItemProps = (dispatch, ownProps) => {
return null;
}
const FilterItem = connect(
mapStateToItemProps,
mapDispatchToItemProps
)(Item)
I suggest you to take a look to this other answer.
You might also be interested in these excellent slides : Big List High Performance React & Redux
And finally, you should definitively take a look to react-virtualized to perform the virtualization of your list (i.e, displaying only the item that the user can actually see).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With