【问题标题】:React.js and big tableReact.js 和大表
【发布时间】:2015-09-11 19:34:51
【问题描述】:

我需要画一张大桌子,不是很大,大约 400x400 个单元格。但是 React 渲染它太慢了,每次点击单元格时,单元格都应该更新,这个更新需要同样大量的时间。有什么建议可以加快速度吗?或者 React 只是不适合此类任务的工具?

这里是示例(表格大小略有减小): https://jsfiddle.net/69z2wepo/15731/

var ROWSC = 400;
var COLSC = 100;

var Hello = React.createClass({
    getInitialState: function () {
        return {
            t: { "1-1": 'c' }
        };
    },
    clicked: function (k) {
        var t = this.state.t;
        t[k] = t[k] ? 0 : 'c';
        this.setState({  t: t  });
    },
    render: function() {
        var items = [];
        for (var r = 0; r < ROWSC; r++) {
            var cols = [];
            for (var c = 0; c < COLSC; c++) {
                var k  = ''+r+'-'+c;
                cols.push(<td key={c} onClick={this.clicked.bind(this,k)} className={this.state.t[k]}>&nbsp;</td>);
            }
            items.push(<tr key={r}>{cols}</tr>);
        }
        return <table>
            {items}
            </table>
        </div>;
    }
});

React.render(<Hello name="World" />, document.getElementById('container'));

【问题讨论】:

  • 嗯,你可以看到这是 O(n^2),400*100 不是那么大,但它仍然是。如果您将其减小到 50*50,您将立即看到差异。此链接上有一个有趣的速度比较,但反应仍然胜过其他东西:codementor.io/reactjs/tutorial/…

标签: javascript reactjs


【解决方案1】:

默认情况下,React 会重新渲染所有内容,但是在存在性能问题的情况下, 可以使用shouldComponentUpdate 函数来确定哪些部分 要在更新时排除的组件树。

在您的示例中,一次只能更新一行,所以 如果我们开始跟踪更新发生在哪一行,我们只能确保 此行已更新。首先,我们必须引入一个新的组件来包装 我们可以放置我们的钩子的表格行。

var Row = React.createClass({
    shouldComponentUpdate: function(nextProps) {
        return nextProps.mustUpdate;
    },
    render: function() {
        return <tr>{this.props.children}</tr>;
    }
});

然后我们可以像这样使用它

items.push(
   <Row key={r}
        mustUpdate={this.state.lastUpdatedRow === r}>
        {cols}
   </Row>);

此外,重新渲染所有这些单元格似乎也是一种浪费,所以我们可以引入 另一个包装表格单元格的组件。

var Cell = React.createClass({
    shouldComponentUpdate: function(nextProps) {
        return this.props.selected !== nextProps.selected;
    },
    render: function() {
        var props = this.props;
        return (
            <td onClick={props.onClick.bind(null, props.col, props.row)} 
                className={props.selected ? 'c' : ''}>&nbsp;
            </td>
        );
    }
});

这应该会显着提高更新的性能。如果还是不行 对于您的特定问题已经足够好,可能 React 不适合您的用例。 无论如何,这就是优化 React 程序的本质,你将组件拆分成更小的 组件并确保仅更新实际更改的部分。

【讨论】:

  • 使用shouldComponentUpdate 提取一些标记到组件中显着提高了速度,但它仍然比jQuery 实现慢。所以结果是 React 不适合这里。
  • @Dfr 好的,我明白了。出于说明目的,这里是显示如何在 React 中回退到原始 DOM 操作的相同示例。如果组件具有某些性能特征,其中原始 DOM 操作最有意义,或者您需要与另一个 DOM 库集成,这可能很有用。 jsfiddle.net/treap/yoLhbzsj
【解决方案2】:

当我在控制台中查看您的结果时,我注意到每次运行 jsfiddle 时都会弹出以下内容:

You are using the in-browser JSX transformer. Be sure to precompile your JSX for production - http://facebook.github.io/react/docs/tooling-integration.html#jsx

我点击链接并看到文档警告使用浏览器内 JSX 转换器时会影响性能:

The in-browser JSX transformer is fairly large and results in extraneous computation client-side that can be avoided. Do not use it in production

也许用 JSX 预编译做另一个测试会让你更好地了解这是否是 React 的一个好的用例。

【讨论】:

【解决方案3】:

两件事:

确保预编译 JSX 以避免这种缓慢。 (在 jsfiddle 中,您会看到一个控制台警告“您正在使用浏览器内的 JSX 转换器。请务必预编译您的 JSX 以用于生产”。

被实现为单个组件,其自身具有单击设置状态,导致组件必须重新处理整个表格(因为setState 触发render 重建表格DOM)。您可以通过创建一个组件来表示每个表格单元格来避免这种情况。然后在您的clicked 函数中,不要在Hello 上调用setState,只需在单击的单元格上调用setState。这样只有更改的单元格才会重新渲染。

这对初始渲染没有帮助,但会因点击而显着加快 UI 更新速度。

【讨论】:

    猜你喜欢
    • 2017-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-27
    • 2017-07-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多