问题描述
我正在为我的应用程序使用带有 react 和 typescript 的 redux.我正在处理在我的应用程序的不同位置使用的许多项目.我的状态是这样的:
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: { ...
},
...
}
用户可以修改items
的一些属性来调度一些动作.发生这种情况时,我需要重新绘制每个页面中已修改的组件.问题是我的项目非常大,我无法在每次小的修改时重新绘制所有项目.我想知道这种方法是否有效:
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
下的树中的所有状态,例如项目 ID 列表:itemsId
. - 在
中,我循环遍历
itemsId
属性以生成多个FilterItem
组件:itemsId.map( itemId=> return );
最后每个
Item
使用ownProps
连接以获得正确的状态部分:
- I have a fist component
<ItemPage1>
which connects to the store to get all of the states stored in the tree underitemPage1
e.g. the list of items id:itemsId
. - Inside
<ItemPage1>
, I loop over theitemsId
property to generate multipleFilterItem
components:itemsId.map( itemId => return <FilterItem id=itemId>);
Finally each
Item
is connected usingownProps
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)
你能否确认或反驳,如果我更新了 id 42 的项目,那么只有这个项目会被重新渲染?
Can you confirm or refute that if I update the item of id 42, then only this item is going to be re-rendered ?
推荐答案
渲染大列表时,您需要考虑以下几点:
When rendering big list you need to take into considerations few things :
- 减少需要渲染的 DOM 元素总数(通过不渲染在屏幕上实际不可见的项目,也称为虚拟化)
- 不要重新渲染没有改变的项目
基本上,您要避免的是在用户编辑一行时完全重新呈现您的列表(或您的页面).这可以完全按照您的方式实现,即:通过仅将需要呈现的项目的 id 传递给列表容器,并使用 将这些 id 映射到
.如果你有一个转储 connect
每个组件>ownProps 组件,你的
组件将创建连接的
connect()
组件.
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.
这将起作用,如果您在 <Item/>
组件类中放置了 console.log('item render')
,您会注意到只有一个电话.
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.
但是(这是一个很大的但是),使用 react-redux
时不明显的是所有依赖于它们的 ownProps状态的任何部分发生变化,/code> 将总是重新渲染.在您的情况下,即使
组件不会重新渲染,它们包装的组件
connect(Item)
也会!如果您有几十个项目,如果需要快速调度操作(例如在输入时输入),您可能会遇到一些延迟.如何避免这种情况?使用工厂函数使用 ownProps
作为初始道具:
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)
我建议你看看这个其他答案.
您可能还对这些优秀的幻灯片感兴趣:Big List High Performance React &还原
You might also be interested in these excellent slides : Big List High Performance React & Redux
最后,你应该明确地看看 react-virtualized 来执行虚拟化您的列表(即,仅显示用户实际可以看到的项目).
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).
这篇关于避免使用 react-redux 重新渲染大量项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!