问题描述
我有一个react组件,每秒都会从redux商店接收道具。新状态的数组与最后一个数组不同。具体而言,每秒都会将一个元素添加到数组中。例如:
在一个状态下数组是:
I have a react component that receives props from the redux store every second. The new state has an array that's different than the last array. To be specific, every second an element is added to the array. For example:in one state the array is:
[1,2,3,4,5,6]
[1, 2, 3, 4, 5, 6]
下一个州
[1,2,3,4,5,6,7]
[1, 2, 3, 4, 5, 6, 7]
我的减速机:
return {
...state,
myList: [ payload, ...state.myList.filter(item => payload.id !== item.id).slice(0, -1) ]
}
现在,在我的react组件中,我订阅了这个状态,每次更改都会重新呈现列表。
Now, in my react component I am subscribing to this state and for every change, the list is re-rendered.
import React, { Component } from 'react';
import MyRow from './MyRow';
class MyList extends Component {
render() {
return (
<div>
{this.props.myList.map((list, index) => (
<MyRow key={list.id} data={list}/>
))}
</div>
);
}
}
function select({ myList }) {
return { myList };
}
export default connect(select)(MyList);
在MyRow.js
import { PureComponent } from 'react';
class MyRow extends PureComponent {
render() {
const data = this.props.data;
return (
<div>
{data.id} - {data.name}
</div>
);
}
}
export default MyRow;
现在,我的问题是:重新渲染已经渲染的每个元素对我来说代价很高。 MyRow大量使用样式组件和其他昂贵的操作。
这导致在状态更新时每秒重新呈现整个列表的反应。如果更新在不到1秒内完成,则会变得更糟,例如每秒4次更新。在这种情况下,react应用程序只会崩溃。
Now, my problem is: It's costly for me to re-render every element that has been already rendered. The MyRow heavily uses styled components and other expensive operations.This is causing react to re-render the whole list every second when the state is updated. This gets worst if updates come in less than 1 seconds, like 4 updates per second. The react app simply crashes in this case.
有没有办法只将新添加的项添加到列表而不重新呈现整个列表?
Is there any way to only add the newly added item to the list and not re-render the whole list?
谢谢
推荐答案
你正在使用,进行浅层比较,然后你的组件 MyRow
应该每个要添加的新项目都会重新呈现不(请按照下面的代码示例)。
You're using PureComponent, that do shallow comparison, then your component MyRow
should not be rerendered on each new item being added (Please follow my code example below).
根据你的问题 - 是的,使用 PureComponent
应该只渲染一次新的item :
According to your question - Yes, using PureComponent
should render only 1 time the new item:
以下是说:
PureComponent :
您可以查看我为您做的代码示例。
Code example of PureComponent
:
You can check out the code sample, that I did for you.
您将看到 Item
组件始终只呈现一次,因为我们使用 React.PureComponent
。为了证明我的陈述,每次渲染 Item
时,我都会添加当前的渲染时间。从示例中您将看到项目
呈现时间:
时间始终相同,因为它已呈现只有一次。
You will see that the Item
component is always rendered only 1 time, because we use React.PureComponent
. To prove my statement, each time the Item
is rendered, I added current time of rendering. From the example you will see that the Item
Rendered at:
time is always the same, because it's rendered only 1 time.
const itemsReducer = (state = [], action) => {
if (action.type === 'ADD_ITEM') return [ ...state, action.payload]
return state
}
const addItem = item => ({
type: 'ADD_ITEM',
payload: item
})
class Item extends React.PureComponent {
render () {
// As you can see here, the `Item` is always rendered only 1 time,
// because we use `React.PureComponent`.
// You can check that the `Item` `Rendered at:` time is always the same.
// If we do it with `React.Component`,
// then the `Item` will be rerendered on each List update.
return <div>{ this.props.name }, Rendered at: { Date.now() }</div>
}
}
class List extends React.Component {
constructor (props) {
super(props)
this.state = { intervalId: null }
this.addItem = this.addItem.bind(this)
}
componentDidMount () {
// Add new item on each 1 second,
// and keep its `id`, in order to clear the interval later
const intervalId = setInterval(this.addItem, 1000)
this.setState({ intervalId })
}
componentWillUnmount () {
// Use intervalId from the state to clear the interval
clearInterval(this.state.intervalId)
}
addItem () {
const id = Date.now()
this.props.addItem({ id, name: `Item - ${id}` })
}
renderItems () {
return this.props.items.map(item => <Item key={item.id} {...item} />)
}
render () {
return <div>{this.renderItems()}</div>
}
}
const mapDispatchToProps = { addItem }
const mapStateToProps = state => ({ items: state })
const ListContainer = ReactRedux.connect(mapStateToProps, mapDispatchToProps)(List)
const Store = Redux.createStore(itemsReducer)
const Provider = ReactRedux.Provider
ReactDOM.render(
<Provider store={Store}>
<ListContainer />
</Provider>,
document.getElementById('container')
)
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/4.0.0/redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-redux/5.0.7/react-redux.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/6.26.0/polyfill.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
- 如果性能问题是由
MyRow
重新发送引起的,请找出原因是什么由于 PureComponent
的使用,因此不应该重新发送。
- 您可以尝试简化 reducer ,以便检查/调试,是导致问题的reducer。例如,只需将新项添加到列表中(不进行任何其他操作,如过滤,切片等):
myList:[... state.myList,payload]
- 请确保您始终将相同的
密钥
传递给您的商品组件< ; MyRow key = {list.id} data = {list} />
。如果更改键
或数据
道具,则会重新呈现该组件。
- If the performance problem is caused by
MyRow
rerending, please find out what's the reason of rerending, because it should not happen, because of PureComponent
usage.- You can try to simplify your reducer, in order to check / debug, is the reducer causing the problem. For instance, just add the new item to the list (without doing anything else as filtrations, slice, etc):
myList: [ ...state.myList, payload ]
- Please make sure you always pass the same
key
to your item component <MyRow key={list.id} data={list} />
. If the key
or data
props are changed, then the component will be rerendered.
-
以下是其他一些库,这些库代表了列表的高效渲染。我相信他们会给我们一些替代或见解:
Here are some other libraries, these stand for efficient rendering of lists. I'm sure they will give us some alternatives or insights:
- - React组件,用于高效呈现大型列表和表格数据
- - 基于UITableView的基于浏览器的高效滚动容器
- react-virtualized - React components for efficiently rendering large lists and tabular data
- react-infinite - A browser-ready efficient scrolling container based on UITableView
这篇关于React / Redux呈现每秒更新的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!