How can I speed up a React render() method that generates a huge DOM? How can I speed up a React render() method that generates a huge DOM? reactjs reactjs

How can I speed up a React render() method that generates a huge DOM?


For this particular case I would recommend react-virtualized or fixed-data-table as mentioned by others. Both components will limit DOM interaction, by lazy loading data, i.e. only render the portion of the table that is visible.

Speaking more generally, the MobX documentation has an excellent page on react performance. Please check it out. Here are the bullet points.

1. Use many small components

mobx-react's @observer components will track all values they use and re-render if any of them changes. So the smaller your components are, the smaller the change they have to re-render; it means that more parts of your user interface have the possibility to render independently of each other.

observer allows components to render independently from their parent

2. Render lists in dedicated components

This is especially true when rendering big collections. React is notoriously bad at rendering large collections as the reconciler has to evaluate the components produced by a collection on each collection change. It is therefore recommended to have components that just map over a collection and render it, and render nothing else:

3. Don't use array indexes as keys

Don't use array indexes or any value that might change in the future as key. Generate id's for your objects if needed. See also this blog.

4. Dereference values lately

When using mobx-react it is recommended to dereference values as late as possible. This is because MobX will re-render components that dereference observable values automatically. If this happens deeper in your component tree, less components have to re-render.

5. Bind functions early

This tip applies to React in general and libraries using PureRenderMixin especially, try to avoid creating new closures in render methods.

Example (untested)

import { observer } from 'mobx-react';import { observable } from 'mobx';const HtmlTable = observer(({  data,}) => {  return (    <table>      <TBody rows={data} />    </table>  );}const TBody = observer(({  rows,}) => {  return (    <tbody>      {rows.map((row, i) => <Row row={row} />)}    </tbody>  );});const Row = observer(({  row,}) => {  return (    <tr key={row.id} style={{height: row.rowHeight + 'px'}}>      {row.cols.map((cell, i) =>         <td key={cell.id}>{cell.value}</td>      )}    </tr>  );});class DataModel {  @observable rows = [    { id: 1, rowHeight: 10, cols: [{ id: 1, value: 'one-1' }, { id: 2, value: 'one-2' }] },    { id: 2, rowHeight: 5,  cols: [{ id: 1, value: 'two-1' }, { id: 2, value: 'two-2' }] },    { id: 3, rowHeight: 10,  cols: [{ id: 1, value: 'three-1' }, { id: 2, value: 'three-2' }] },  ];  @observable rowLimit = 10;  @observable colLimit = 10;  @computed  get limitedRows() {    return this.limitData(this.rows, this.rowLimit).map(r => {      return { id: r.id, cols: this.limitData(r.col, this.colLimit) };    });  }  limitData(data, limit) {    return limit ? data.slice(0, limit) : data;  }}const data = new DataModel();React.render(<HtmlTable data={data.limitedRows} />, document.body);

sources:


Make each row as a subcomponent and pass the props to that subcomponent.That subcomponent will have its own state and can change without affecting all the rows

class HtmlTable extends React.Component {   render() {       var {rowCount, colCount, data} = this.props;       var rows = this.limitData(data, rowCount);       return <table>           <tbody>{rows.map((row, i) => {               var cols = this.limitData(row, colCount);               return (<Row cols={cols} key={i}/>)           })}</tbody>       </table>   }   shouldComponentUpdate() {       return false;   }   limitData(data, limit) {       return limit ? data.slice(0, limit) : data;   }}


You should investigate on how to perform reconciliation within a worker (or a pool thereof) and transfer the result back to your main thread. There exists a project that attempts to do just that, so you can experiment with their implementation.

Please note that I belong to the majority that has never encountered such requirements with React as yourself, so I can't provide any implementation details or further hints, but I believe web-perf/react-worker-dom may be a good place to start to start exploring and discovering similar solutions.