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...

相關文章
相關標籤/搜索