React and Redux 性能,框架优化总结
aototo opened this issue · 3 comments
React and Redux 性能,框架优化总结
React
-
利用React Server Render 提高首屏的渲染速度
- 利于SEO
- 加速首屏的渲染时间
- 前后端共享数据源
使用
Reacr.renderToString
,React.renderToStaticMarkup
。 -
请将方法的bind一律置于
constructor
,避免多次bind。 -
请只传递component需要的props ,切勿一股脑的
<Component {...props} />
。 -
不需要传入状态的component写成
const element
的形式,这样能加快这个element的初始渲染速度。 -
dom上设置可被react识别的同级唯一
key
,否则情况可能不会重新渲染。 -
使用`Stateless Functional Component 无状态组件
- Class并无必要
- 没有this关键字
- 无状态组件写起来代码量更少,
- 便于测试
React 的无状态组件优雅的实现可复用组件的方式。
栗子如下:
const Pane = (props) => <div>{props.children}</div>;
Pane.propTypes = {
label: React.PropTypes.string.isRequired,
children: React.PropTypes.element.isRequired
};
-
使用
pureRender
,避免组件没有意义的渲染,配合immutable,减少渲染。 -
使用react-css-modules,解决了命名混乱,全局污染以及依赖管理的问题,多人协同开发有时候难免会发生样式上的冲突。
有个需要注意的地方,下面的2个顺序如果颠倒,就会出错。
@connect(mapStateToProps, mapDispatchToProps)
@CSSModules(styles)
React-router && Webpack
按需加载模块
把这个按需写着这里,本身需要react-router支持,索性就放在这边了。
加载函数:
require.ensure(dependencies, callback, chunkName)
//这里react-router 使用require.ensure,当然了webpack需要配置一下。
<Route path="home" getComponent={(location, callback) => {
require.ensure([], require => {
callback(null, require('modules/home'))
}, 'home')
}}></Route>
具体看webpack官方
看不懂看这篇webpack 按需打包
Redux
Data
项目数据扁平化,不扁平化带来的问题:
- 数据拷贝比较更耗时
- 获取数据的时候比较麻烦
通过redux 的combineReducers
可以很好的扁平化数据。如果使用immutable的话整个侵入性非常的强,不仅要修改combineReducers(因为combineReducers实现就是可变的数据),还需要注意获取数据的时候是否是不可变,以免是null。如果使用immutable可以推荐使用redux-immutable。
return {
...state,
newData
}
上面这种写法本身也算是一种immutable,但是要求数据层级不能太深。如果数据相对复杂建议使用immutable。
推荐pure-render-decorator方便的来控制组件渲染。
import pureRender from 'pure-render-decorator';
@pureRender
class ...
使用immutable的时候数据转换如下:
- 可变转不变可以在redux的reducer执行
- 不变转可变在mapStateToProps and getState()执行
immutableJs
Immutable 详解及 React 中实践
redux-immutable
seamless-immutable体积更小,兼容相对好。只支持Arrays and Objects。
数据筛选reselect
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
每当store发生改变的时候,connect就会触发重新计算,为了减少重复的不必要计算,减少大型项目的性能开支,需要对selector函数做缓存。推荐使用reactjs/reselect, 缓存的部分实现代码如下。
export function defaultMemoize(func, equalityCheck = defaultEqualityCheck) {
let lastArgs = null
let lastResult = null
const isEqualToLastArg = (value, index) => equalityCheck(value, lastArgs[index])
return (...args) => {
if (
lastArgs === null ||
lastArgs.length !== args.length ||
!args.every(isEqualToLastArg)
) {
lastResult = func(...args)
}
lastArgs = args
return lastResult
}
}
If the values of the input-selectors are the same as the previous call to the selector, it will return the previously computed value instead of calling the transform function.
假如state.todos 中todos 提供的数据没有发生改变,就会return之前计算好的结果,这样就可以少去非常多的计算成本。
具体的实现可以去看https://github.com/reactjs/reselect#creating-a-memoized-selector。
具体用法:以下修改reudx官方的的demo
import { createSelector } from 'reselect'
const getVisibilityFilter = (state) => state.visibilityFilter
const getTodos = (state) => state.todos
export const getVisibleTodos = createSelector(
[ getVisibilityFilter, getTodos ],
(visibilityFilter, todos) => {
switch (visibilityFilter) {
case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
return todos.filter(t => !t.completed)
}
}
)
Batched actions
如果我们需要同时发送很多action,比如:
dispatch(action1)
dispatch(action2)
dispatch(action3)
可以减少不必要的计算,推荐用到redux-batched-actions
dispatch(batchActions[action1, action2, action3])
源码很简单
https://github.com/tshelburne/redux-batched-actions/blob/master/src/index.js#L7
Redux DevTools
开发中使用DevTools,建议使用谷歌的插件,不建议在页面结构中插入DevTools。
redux-devtools-extension
在开发环境以及产品环境中移除devTools,避免不必要性能开销和文件大小。
栗子如下:
if (process.env.NODE_ENV === 'production') {
module.exports = require('./configureStore.prod');
} else {
module.exports = require('./configureStore.dev');
}
注意: 需要在webpack中使用DefinePlugin
插件。
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
相关
- 移动端开发的时候请禁止redux-devtools,会造成卡顿
以往收集的文章,博客
阮一峰的redux 入门
ReactJS组件间沟通的一些方法
聊一聊基于Flux的前端系统
React 性能工程
聊一聊基于Flux的前端系统
React性能工程-- 深入研究React性能调试
A Better File Structure For React/Redux Applications
React服务器端渲染实践小结
dva 项目解决方案
Getting Started with Redux
React 实践心得:react-redux 之 connect 方法详解
REACT&REDUX中SCROLL LIST封装实践
redux-axios-middleware axios兼容ie9,提供promise ,很方便。
深入理解 react-router 路由系统
Immutable 详解及 React 中实践
webpack+ react-router 按需加载
大概的整个项目具体的优化就这些,细节的插件和实施大家自己去看文档。后续继续更新,喜欢的朋友star支持一下。
@asd0102433
通过redux 的combineReducers 可以很好的扁平化数据。如果使用immutable的话整个侵入性非常的强,不仅要修改combineReducers(因为combineReducers实现就是可变的数据),还需要注意获取数据的时候是否是不可变,以免是null。如果使用immutable可以推荐使用redux-immutable
这是说引入了redux-immutable
替代了redux自己的combineReducers
后,还需要手动引入immutablejs
库?
@tangkunyin 需要哈!
@asd0102433 三克斯