sbi*_*nko 23 javascript performance reactjs
HtmlTable组件想象一下简单的HtmlTableReact组件.它根据通过dataprop 传递给它的二维数组呈现数据,并且还可以限制通过rowCount和colCount道具的列数和行数.此外,我们需要组件处理大量数据(数万行)而不需要分页.
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 <tr key={i}>{cols.map((cell, i) => {
return <td key={i}>{cell}</td>
})}</tr>
})}</tbody>
</table>
}
shouldComponentUpdate() {
return false;
}
limitData(data, limit) {
return limit ? data.slice(0, limit) : data;
}
}
Run Code Online (Sandbox Code Playgroud)
rowHeights道具现在我们想让用户更改行高并动态执行.我们添加一个rowHeightsprop,它是行索引到行高的映射:
{
1: 100,
4: 10,
21: 312
}
Run Code Online (Sandbox Code Playgroud)
如果为其索引指定了高度(我们也使用for ),我们更改我们的render方法以添加styleprop :<tr>shallowCompareshouldComponentUpdate
render() {
var {rowCount, colCount, data, rowHeights} = this.props;
var rows = this.limitData(data, rowCount);
return <table>
<tbody>{rows.map((row, i) => {
var cols = this.limitData(row, colCount);
var style = rowHeights[i] ? {height: rowHeights[i] + 'px'} : void 0;
return <tr style={style} key={i}>{cols.map((cell, i) => {
return <td key={i}>{cell}</td>
})}</tr>
})}</tbody>
</table>
}
shouldComponentUpdate(nextProps, nextState) {
return shallowCompare(this, nextProps, nextState);
}
Run Code Online (Sandbox Code Playgroud)
因此,如果用户传递rowHeights带有值的道具{1: 10},我们只需要更新一行 - 第二行.
但是,为了做差异,React必须重新运行整个渲染方法并重新创建成千上万的<tr>s.这对于大型数据集来说非常慢.
我想过使用shouldComponentUpdate,但它没有帮助 - 瓶颈发生在我们甚至尝试更新之前<tr>.在整个桌子的重新创建过程中发生了瓶颈,以便进行差异化.
我想到的另一件事是缓存render结果,然后splice更改行,但似乎完全没有使用React的目的.
有没有办法不重新运行"大" render功能,如果我知道只有一小部分会改变?
编辑:显然,缓存是要走的路......例如,这里讨论了React的Github中的类似问题.而React Virtualized似乎正在使用一个单元缓存(尽管我可能会遗漏一些东西).
编辑2:不是.存储和重用组件的"标记"仍然很慢.其中大部分来自协调DOM,这是我应该期待的.好吧,现在我完全迷失了.这就是我准备"标记"所做的:
componentWillMount() {
var {rowCount, colCount, data, rowHeights={}} = this.props;
var rows = this.limitData(data, rowCount);
this.content = <table>
<tbody>{rows.map((row, i) => {
var cols = this.limitData(row, colCount);
var style = rowHeights[i] ? {height: rowHeights[i] + 'px'} : void 0;
return <tr style={style} key={i}>{cols.map((cell, i) => {
return <td key={i}>{cell}</td>
})}</tr>
})}</tbody>
</table>
}
render() {
return this.content
}
Run Code Online (Sandbox Code Playgroud)
Kyl*_*ley 18
对于这种特殊情况,我建议其他人提到的react-virtualized或fixed-data-table.两个组件都将通过延迟加载数据来限制DOM交互,即仅渲染表中可见的部分.
更一般地说,MobX文档有一个关于反应性能的出色页面.请检查一下.以下是要点.
mobx-react的
@observer组件将跟踪它们使用的所有值,并在其中任何值发生变化时重新呈现.因此,组件越小,重新渲染的变化就越小; 这意味着您的用户界面的更多部分可以彼此独立地呈现.
observer允许组件独立于其父级进行渲染
渲染大型集合时尤其如此.React在渲染大型集合方面是出了名的糟糕,因为协调程序必须在每次集合更改时评估集合生成的组件.因此,建议使用仅映射集合并对其进行渲染的组件,并不再渲染其他内容:
不要使用数组索引或将来可能更改的任何值作为键.如果需要,为您的对象生成id.另见此博客.
当使用mobx-react时,建议尽可能晚地取消引用值.这是因为MobX将重新呈现自动取消引用可观察值的组件.如果在组件树中更深层次地发生这种情况,则需要重新渲染的组件越少.
本技巧一般适用于React和使用PureRenderMixin的库,尽量避免在渲染方法中创建新的闭包.
示例(未经测试)
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);
Run Code Online (Sandbox Code Playgroud)
来源:
将每一行作为子组件并将 props 传递给该子组件。该子组件将拥有自己的状态,并且可以在不影响所有行的情况下进行更改
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;
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2519 次 |
| 最近记录: |