React / Redux呈现每秒更新的列表 [英] React/Redux rendering a list that's updating every second

查看:123
本文介绍了React / Redux呈现每秒更新的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个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?

谢谢

推荐答案

你正在使用 PureComponent ,进行浅层比较,然后你的组件 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).


有没有办法只将新添加的项添加到列表中而不重新渲染整个列表?

Is there any way to only add the newly added item to the list and not re-render the whole list?

根据你的问题 - 是的,使用 PureComponent 应该只渲染一次新的item

According to your question - Yes, using PureComponent should render only 1 time the new item:

以下是 React的文档说:


如果你的React组件的render()函数给出相同的结果,给出相同的道具和在某些情况下,你可以使用React.PureComponent来提升性能。

If your React component’s render() function renders the same result given the same props and state, you can use React.PureComponent for a performance boost in some cases.



PureComponent <的代码示例/ code>:



您可以查看我为您做的代码示例。

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>


  1. 如果性能问题是由 MyRow 重新发送引起的,请找出原因是什么由于 PureComponent 的使用,因此不应该重新发送。


    • 您可以尝试简化 reducer ,以便检查/调试,是导致问题的reducer。例如,只需将新项添加到列表中(不进行任何其他操作,如过滤,切片等): myList:[... state.myList,payload]

    • 请确保您始终将相同的 密钥 传递给您的商品组件< ; MyRow key = {list.id} data = {list} /> 。如果更改数据道具,则会重新呈现该组件。

  1. 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.








  1. 以下是其他一些库,这些库代表了列表的高效渲染。我相信他们会给我们一些替代或见解:

  1. Here are some other libraries, these stand for efficient rendering of lists. I'm sure they will give us some alternatives or insights:

  • 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呈现每秒更新的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆