React/Redux rendering a list that's updating every second

react-redux example
react-redux example code
react-redux real world example
redux performance large data
react redux tutorial 2018
react-redux todo app tutorial
react-redux example with api calls
react native redux example

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]

the next state

[1, 2, 3, 4, 5, 6, 7]

My reducer:

return {
  ...state,
  myList: [ payload, ...state.myList.filter(item => payload.id !== item.id).slice(0, -1) ]
}

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);

In 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;

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?

Thanks

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?

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

Here's what the React's docs says:

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.

Code example of PureComponent:

You can check out the code sample, that I did for you.

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>

Example: Todo List, import { render } from 'react-dom'. import { Provider } from 'react-redux'. import { createStore } from 'redux'. import rootReducer from './reducers'. import App from '. Consider this react-redux implementation of rendering a list of DOM elements to display animals for adoption. The important stuff is in the Props and Handlers interfaces. We get most of what we need to know from the Props and Handlers interfaces: AnimalTable accepts an immutable map of Animals.

PureComponent will shallowly compare the props and state. So my guess here is that the items are somehow new objects than the previous passed props, thus the rerendering.

I would advice, in general, to only pass primitive values in pure components :

class MyList extends Component {
    render() {
        return (
            <div>
                {this.props.myList.map((item, index) => (
                    <MyRow key={item.id} id={item.id} name={data.name} />
                    //or it's alternative 
                    <MyRow key={item.id} {...item} />
                ))}
            </div>
        );
    }
}

//...

class MyRow extends PureComponent {
    render() {
        const {id, name} = this.props;
        return (
            <div>
                {id} - {name}
            </div>
        );
    }
}

React/Redux rendering a list that's updating every second, You're using PureComponent, that do shallow comparison, then your component MyRow should not be rerendered on each new item being  Rendering A List With React Summary As we have seen rendering a list in React is not so bad. While React does not have the syntactic sugar of ng-for or v-for, we can simply use the JavaScript map function to produce the same effect.

There is quite an easy solution for this. React VDOM is just a diffing algorithm. The only piece missing with your JSX is something called key which is like an id that the diffing algo uses and renders the particular element. Just tag the element with a KEY something like this https://reactjs.org/docs/lists-and-keys.html#keys

<li key={number.toString()}>
    {number}   </li>

The best way of rendering a collection of items in React/Redux, In short. The best way to render a collection in React, backed by Redux or other similar library: store a collection as an object where key is item id and value is item itself. That way when rendering collection, pass only item's id to the item component. How to sort list – react-redux example We have created a React Application that connects with Redux , then filter list of items with input text . In this tutorial, we continue to sort that list using react-redux.

The problem really exists in the reducer.

myList: [ payload, ...state.myList.filter(item => payload.id !== item.id).slice(0, -1) ]

What is the logic implemented using slice(0,-1)?

It is the culprit here.

From your question I understood the next state after [1,2,3] will be [1,2,3,4].

But your code will be giving [4,1,2], then [5,4,1] then [6,5,4].

Now all the elements in the state are new, not in the initial state. See state is not just getting appended it is completely changing.

Please see if you are getting the desired result by avoiding slice.

 myList: [ payload, ...state.myList.filter(item => payload.id !== item.id)]

Lists and Keys – React, In React, transforming arrays into lists of elements is nearly identical. Rendering Multiple Components Usually you would render lists inside a component. Rendering List of Elements in React With JSX. Understanding how JSX is processed can be slightly tricky to understand. Knowing when its appropriate to use JavaScript code and when to use HTML in your JSX can be very nuanced when writing React code.

it looks like you are creating a new array each time in the reducer in which all array indices need to be re-calculated. have you tried appending the new node to the end of the list instead of prepending?

3 small tips for better Redux performance in a React app, In React, we translate optimisations into rendering time reduction and reduction of overall renders. The former has to do with the amount of work that is performed​  Technically, a container component is just a React component that uses store.subscribe() to read a part of the Redux state tree and supply props to a presentational component it renders. You could write a container component by hand, but we suggest instead generating container components with the React Redux library's connect() function, which provides many useful optimizations to prevent unnecessary re-renders.

Redux ruins your React app performance? You are doing something , It will pretty print properties, that caused your component to re-render. Try to put this import {connect} from 'react-redux';const element = <List />;export default​  If you choose not to assign an explicit key to list items then React will default to using indexes as keys. Here is an in-depth explanation about why keys are necessary if you’re interested in learning more. Extracting Components with Keys . Keys only make sense in the context of the surrounding array.

Practical Redux, Part 6: Connected Lists, Forms, and Performance , This time, we'll connect lists and forms directly to Redux, discuss By default, whenever a React component re-renders, React will re-render all  Conditional Rendering. In React, you can create distinct components that encapsulate behavior you need. Then, you can render only some of them, depending on the state of your application. Conditional rendering in React works the same way conditions work in JavaScript.

How to Display a List in React, The first time a component like IdiomaticReactList is rendered, React will see that you want to render a bunch of items, and it will create DOM  Hey gang, in this React tutorial I'll introduce you to the concept of cycling through lists of data and outputting that data in the component template. To do this, we'll use the map function

Comments
  • Really good article about performance optimization you can find here.
  • Looks like your using keys correctly this allows react to understand which elements are new as such the vDOM should not re render all the items rather update as required reactjs.org/docs/lists-and-keys.html.
  • @Reza can you please checkout my detailed answer, and if there's something unclear, then please let me know.
  • Without PureComponent, each Item in the List will be rerendered, on a new Item being added. You can play with my example above. So PureComponent is required.
  • Yeah. My mistake. Edited the answer. Thanks
  • Isn't this going to mutate the state? Also, array keys are fixed values from DB.
  • it mutates the redux state, yes, but I don't think state mutation is what causes your issue. I suspect that in your reducer, when receiving the action and calculating myList, you force React to re-render everything because the first, and all, items in the array change. if you were to append payload, versus prepend payload, React may be able to better handle your new data.
  • The original question is the right way to handle redux state. It's only making a shallow copy (even though the values are primitives, not references, so they'll pass === no matter what)