React移动项目总结

前端之家收集整理的这篇文章主要介绍了React移动项目总结前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

React移动项目总结

背景

接触React半年了,一路走过来,团队做了几个项目,不断的总结经验,不断的重构,也看了很多大牛总结的react经验。
尝试把自己遇到的问题总结分享出来,希望更多前辈指导指导。

总结基于两个项目

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

  • 下单系统

  • Mac下开发

    js

    react

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

    有自己团队的一套简单的规范standard,就是airbnb搬过来的

    redux

    用redux做数据流,redux-thunk做异步。

    貌似actions reducers没法异步按需加载,于是自己倒腾了异步加载的redux-async-actions-reducers

    and 如果你的应用不够大的话,就没有必要异步加载了,比如手机web。 全部打包也不会很大。

    比如说下单系统的公共文件 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...

    猜你在找的React相关文章