React移动项目总结

React移动项目总结

背景

接触React半年了,一路走过来,团队作了几个项目,不断的总结经验,不断的重构,也看了不少大牛总结的react经验。
尝试把本身遇到的问题总结分享出来,但愿更多前辈指导指导。javascript

总结基于两个项目css

  • react-mgm 代码在Github上,一个组件库,包括了大部分的总结内容,内部的demo也算一个小SPA项目。html

  • 下单系统java

Mac下开发react

js

react

用class的写法写组件,和React.createClass不太同样。具体babel有文字介绍react-on-es6-plusandroid

有本身团队的一套简单的规范standard,就是airbnb搬过来的webpack

redux

用redux作数据流,redux-thunk作异步。css3

貌似actions reducers无法异步按需加载,因而本身倒腾了异步加载的redux-async-actions-reducersgit

and 若是你的应用不够大的话,就没有必要异步加载了,好比手机web。 所有打包也不会很大。es6

好比说下单系统的公共文件 common.xxxx.js 占了80%的代码量,在开发的时候达到1.4M,webpack -p 后是 500+kb,通过gzip压缩以后是100kb。因此文件大小压根不是什么事,没有必要纠结太多。以前是否使用immutable就纠结了好久。

然而,更多应该关注到js的执行时间上,css和html的渲染处理上,文件大小真的没有这么重要。

react-router

browserHistory须要后台配合,因此用了hashHistory。 但确定前者更友好。

路由过场动画react-addons-css-transition-group。作到了想微信那样前进后退的切换,很爽。(后来考虑到移动端性能不足问题,没有采用动画)

class App extends React.Component{
    render(){
        const action = this.props.location.action;
        let transitionName = 'page';
        // REPLEASE
        if (action === 'PUSH') {
            transitionName = 'page-r2l';
        } else if (action === 'POP') {
            transitionName = 'page-l2r';
        }
        return (
            <ReactCSSTransitionGroup
                component="div"
                transitionName={transitionName}
                transitionEnterTimeout={200}
                transitionLeaveTimeout={200}
            >
                {React.cloneElement(this.props.children, {
                    key: this.props.location.pathname
                })}
            </ReactCSSTransitionGroup>
        );
    }
}

es6/7

写代码太爽了,跟着潮流走。须要在.babelrc文件上配置好

{
  "presets": [
    "react",
    "es2015",
    "stage-0"
  ]
}

至于es7的stage-x是啥,看http://www.csdn.net/article/2...。也能够无脑的设置stage-0

immutable

确实是会由于一些引用问题致使数据不正确,问题难以发现和排查。和组件的屡次渲染。

因而引用immutable,须要克服的是团队的接受能力,须要点学习成本,可是带来的性能提高是很高的(作shouleComponentUpdate)。

至于不少人都提到包大小问题,我的认为不用担忧,webpack -p压缩+gzip,基本压到很小的体积。个人在120kb,这但是所有代码(js+css)啊。

fastclick

在移动端会点击延迟,缘由百度吧。用了react-fastclick来处理,具体看这里 移动端300ms点击延迟和点击穿透问题

兼容

项目用了不少es6特性,浏览器不支持。能够引入 babel-polyfill。
固然babel-polyfill比较大,你也能够根据项目的具体状况来引入指定的方法。如core-js/es6/object.js core-js/es6/promise.js等等

直接和commons一块儿打包便可

entry: {
    'commons': [
        'core-js/es6/object.js',
        'core-js/es6/promise.js',
        ...
    ]
}

btw,我在移动端口的时候引入core-js的2.x版本,直接就报错了。 遇到的同窗能够降级到1.x版本。(具体缘由尚未排查)

若是须要兼容到ie,听说有挺多坑。 推荐看下这篇文章使用ES6的浏览器兼容性问题

css

产品主要场景在微信端,因此选择了weui,使用的感受是目前weui提供的组件相对少,可是足够用。weui的克制也保证了weui的质量。有时候读代码时候发现weui确实沉淀了不少精华在里面。 配色方面基于weui作改造覆盖,因此咱们选择了引入weui的less,方便用里面的已经定义好的变量。

用了大量的Flex布局,很灵活,下降CSS难度。

字体文件用了阿里的iconfont。 收集好图片下载下来,推送到github,而后在发布到npm。

border

Retina屏的boder和pc的不同。 有不少解决方案,能够参考weui对于border的处理。 还能够看这里 Retina屏的移动设备如何实现真正1px的线

而后实践过程当中1px遇到的问题远不止于此,上一个连接提到的只是点也不够全面,独立总结了下 移动端1px border

构建

babel

babel作es6/7的转换,之前通常在loaders上直接写babel的配置,好比

// 写在webpack.config.js中
loaders: [{
    test: /\.js$/,
    loader: 'babel?presets[]=react,presets[]=es2015,presets[]=stage-0'
}]

如今切换到用.babelrc配置上.(也是官方推荐的方法)

{
  "presets": [
    "react",
    "es2015",
    "stage-0"
  ]
}

热加载

能够在webpack.config.dev.js中配置,不过用命令行的形式更简洁

webpack-dev-server --inline --hot ...

css

用了postcss来处理css3的兼容性。

然而你可能会有机会发现开发的时候会生成 -webkit-flex 这种前缀,发布后却丢失了。(日了狗)也许是国外的浏览器环境及比较好(国内android被微信内置浏览器统一了,iOS微信还有大约10%的iOS8的用户,有些css属性须要-webkit-前缀)

鉴于此,特别注意这个写法css?-autoprefixer,具体看-webkit-flex 被移除了

js版本控制

官方介绍的很详细 long-term-caching

用hash作js的版本号,经过AssetsPlugin生成记录版本号的文件build/webpack-assets.js,而后页面引入这个文件就能够获得js文件的版本号了。

output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].[hash].js',
    publicPath: '/react-mgm/build/'
},
plugins: [
    new webpack.NoErrorsPlugin(),
    new AssetsPlugin({
        filename: 'build/webpack-assets.js',
        processOutput: function (assets) {
            return 'window.WEBPACK_ASSETS = ' + JSON.stringify(assets);
        }
    })
],
// index.html
<script>
    document.write('<script src="../build/webpack-assets.js"><\/script>');
</script>
<script
    document.write('<script src="' + window.WEBPACK_ASSETS['index'].js + '"><\/script>');
</script>

公共文件commons处理


webpack commons hash
如何肯定哪些文件应该打包在commons

构建加速

1
http://webpack.github.io/docs...
devtool 设置 eval

2
一些文件直接引用打包好的版本能够加快构建。

module: {
    (...省略)
    noParse: [
        // 'react/dist/react.min.js',
        // 'react-dom/dist/react-dom.min.js',
        'react-router/umd/ReactRouter.min.js',
        'redux/dist/redux.min.js',
        'react-redux/dist/react-redux.min.js',
        'underscore/underscore-min.js'
    ]
},
resolve: {
    alias: {
        // react 无法加速build,由于react-addons-css-transition-group
        // 'react': 'react/dist/react.min.js',
        // 'react-dom': 'react-dom/dist/react-dom.min.js',
        'react-router': 'react-router/umd/ReactRouter.min.js',
        'redux': 'redux/dist/redux.min.js',
        'react-redux': 'react-redux/dist/react-redux.min.js',
        'underscore': 'underscore/underscore-min.js'
    }
},

构建环境

目前知道须要设置两个地方,命令行中加入 NODE_ENV

NODE_ENV=production webpack xxxxx

and webpack配置里面加入plugin,这样代码就能经过if(__DEBUG__)这种代码作环境差别。

new webpack.DefinePlugin({
    __DEBUG__: env === 'development' ? true : false,
    "process.env": { // 干掉 https://fb.me/react-minification 提示
        NODE_ENV: env === 'development' ? JSON.stringify("development") : JSON.stringify("production")
    }
})

打包库文件

webpack.config.js webpack.config.min.js
有些库做为依赖项,不该该打包进库文件中,用externals来描述

externals: {
    'react': 'react',
    'react-dom': 'react-dom',
    'underscore': 'underscore',
    'classnames': 'classnames'
},

css文件独立打包,用ExtractTextPlugin来描述。

最后作压缩

new webpack.optimize.UglifyJsPlugin({
    compressor: {
        screw_ie8: true,
        warnings: false
    }
})

npm

用了npm script来统一开发规范。
npm start来开启开发
npm run deploy来发布
npm run publishpatch来发布到npm,并同步到淘宝镜像来作加速

"scripts": {
    "precommit": "eslint ./src/component/",
    "pre": "npm install;",
    "clear": "rm -rf build; mkdir build;",
    "start": "npm run clear; webpack-dev-server --config webpack.config.dev.js --port 4000 --host 0.0.0.0 --inline --hot --devtool eval --progress --color --profile",
    "deploy": "npm install; npm run build && npm run build:min",
    "build": "webpack --progress --color --profile",
    "build:min": "webpack --config webpack.config.min.js",
    "publishpatch": "npm run deploy; git add --all; git commit -m 'c'; npm version patch; git push origin master:master; npm publish; npm publish --registry='https://registry.npmjs.org'; cnpm sync react-mgm; npm version;"
  },

另外在项目中遇到版本依赖的问题。开发的时候好好的,发布后就出问题了。 缘由是npm依赖不一致问题。要么固定版本号,可是只能固定项目的依赖,依赖的依赖就无法固定了。 有个方案不错 npm shrinkwrap

规范

eslint

安装npm install husky的时候会自动往你的git hooks上加代码,提交代码的时候触发想要的npm scripts。

咱们用eslint来作检测,配置见package.json的npm run precommit

eslint的配置用eslintrc.js官方推荐的写法,具体配置弄成一个本身的库了。

用了eslint推荐的配置再结合eslint-plugin-react的配置

具体见eslint-plugin-gm

module.exports = {
    "plugins": [
        "gm"
    ],
    "extends": ["plugin:gm/recommended"]
}

server服务

在开发时间避免等后台api,找了json-server来作api服务,rest风格,很方便。
等后台ready了,再经过上面提到的server代理调用联调。

性能优化

react性能优化

其余

键盘呼气

若是你的输入框比较低的话,键盘呼气就会挡住输入框。 iphone会自动把input移到可见的位置,而android不会。 能够在android上对输入框使用 scrollIntoViewIfNeed 使元素可见。

and在react下,会出现原本点输入框的,结果倒是点了其余东西,触发其余逻辑了。 因此这里就搞了500ms的延迟。

自动呼气键盘

在android键盘须要用户触发才能够呼气。iOS 加个autoFocus便可。

判断元素可见

一开始是慢慢的算offsetTop,若是层次很深的话,还要算多个parent的offsetTop,而后才能得出,如此必然很烦。 能够用 getBoundingClientRect 便可。

微信title的处理

https://segmentfault.com/a/11...

相关文章
相关标签/搜索