大幅提升 React 性能的6个建议

React 在不做任何优化的情况下性能也非常好,然而通过一些小小的优化,可以让性能进一步提升,通过以下这6条建议,可以数十倍加快渲染速度

设置 NODE_ENV 为 Production

React 在开发环境下,有完整的警告和错误检查,但它们不是为生产环境准备的,如果你看过 React 的源码,你会看到很多 if (process.env.NODE_ENV != 'production'),这些代码对于最终用户是不需要的,而且访问 process.env.NODE_ENV 会非常慢,对于生产环境而言,完全可以移除这些代码

如果你使用 Webpack,你可以使用 DefinePlugin 来替换 process.env.NODE_ENV 为 ‘production’,然后使用 UglifyJsPlugin 移除这些不会执行的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
// webpack.config.js
...
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
]
...

React 15 的渲染速度比 0.14 快约 25%

React 15 的更新中非常重要的一项是,使用在现代化浏览器中性能更好的 document.createElement 替换 innerHTML,这一改动也意味着 React 将不再支持 IE8

Babel Constant 和 Inline Elements 转换

Babel 为开发者们提供了 React Constant ElementsReact Inline Elements,这两款插件能够在编译阶段将代码转换成更高效的形式,注意仅将它们用于生产环境

封装集合渲染为独立组件

这一点在循环渲染集合组件时尤其重要,React 在渲染大型集合是性能十分糟糕,原因是 React 会在每次更新中全部重新渲染,因此建议将渲染集合的部分装为独立的组件渲染

1
2
3
4
5
6
7
8
9
10
11
12
// Bad
class MyComponent extends Component {
render() {
const {todos, user} = this.props;
return (<div>
{user.name}
<ul>
{todos.map(todo => <TodoView todo={todo} key={todo.id} />)}
</ul>
</div>)
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Good
// 当 user.name 更新时,列表不会重新渲染
class MyComponent extends Component {
render() {
const {todos, user} = this.props;
return (<div>
{user.name}
<TodosView todos={todos} />
</div>)
}
}
class TodosView extends Component {
render() {
const {todos} = this.props;
return (<ul>
{todos.map(todo => <TodoView todo={todo} key={todo.id} />)}
</ul>)
}
}

尽早绑定方法

在 render() 中绑定的方法应该尽早声明,而不是在渲染时定义

1
2
3
4
// Bad
render() {
return <MyWidget onClick={() => { alert(this.state.text) }} />
}

1
2
3
4
5
6
7
8
9
10
11
12
// Good
constructor() {
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.text);
}
render() {
return <MyWidget onClick={this.handleClick} />
}

不变组件禁用更新

对于不需要更新的组件,可以在 shouldComponentUpdate()return false,或者使用 Stateless Component

1
2
3
4
5
6
// Bad
class Logo extends Component {
render() {
return <div><img src='logo.png' /></div>;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
// Good
class Logo extends Component {
shouldComponentUpdate() {
return false;
}
render() {
return <div><img src='logo.png' /></div>;
}
}
// or Stateless Component
const Logo = () => <div><img src='logo.png' /></div>;
参考文章