接觸React半年了,一路走過來,團隊作了幾個項目,不斷的總結經驗,不斷的重構,也看了不少大牛總結的react經驗。
嘗試把本身遇到的問題總結分享出來,但願更多前輩指導指導。javascript
總結基於兩個項目css
Mac下開發react
用class的寫法寫組件,和React.createClass不太同樣。具體babel有文字介紹react-on-es6-plusandroid
有本身團隊的一套簡單的規範standard,就是airbnb搬過來的webpack
用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的渲染處理上,文件大小真的沒有這麼重要。
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> ); } }
寫代碼太爽了,跟着潮流走。須要在.babelrc
文件上配置好
{ "presets": [ "react", "es2015", "stage-0" ] }
至於es7的stage-x是啥,看http://www.csdn.net/article/2...。也能夠無腦的設置stage-0
確實是會由於一些引用問題致使數據不正確,問題難以發現和排查。和組件的屢次渲染。
因而引用immutable,須要克服的是團隊的接受能力,須要點學習成本,可是帶來的性能提高是很高的(作shouleComponentUpdate)。
至於不少人都提到包大小問題,我的認爲不用擔憂,webpack -p壓縮+gzip,基本壓到很小的體積。個人在120kb,這但是所有代碼(js+css)啊。
在移動端會點擊延遲,緣由百度吧。用了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的瀏覽器兼容性問題
產品主要場景在微信端,因此選擇了weui
,使用的感受是目前weui提供的組件相對少,可是足夠用。weui的剋制也保證了weui的質量。有時候讀代碼時候發現weui確實沉澱了不少精華在裏面。 配色方面基於weui作改造覆蓋,因此咱們選擇了引入weui的less,方便用裏面的已經定義好的變量。
用了大量的Flex佈局,很靈活,下降CSS難度。
字體文件用了阿里的iconfont。 收集好圖片下載下來,推送到github,而後在發佈到npm。
Retina屏的boder和pc的不同。 有不少解決方案,能夠參考weui對於border的處理。 還能夠看這裏 Retina屏的移動設備如何實現真正1px的線
而後實踐過程當中1px遇到的問題遠不止於此,上一個連接提到的只是點也不夠全面,獨立總結了下 移動端1px border
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 ...
用了postcss
來處理css3的兼容性。
然而你可能會有機會發現開發的時候會生成 -webkit-flex 這種前綴,發佈後卻丟失了。(日了狗)也許是國外的瀏覽器環境及比較好(國內android被微信內置瀏覽器統一了,iOS微信還有大約10%的iOS8的用戶,有些css屬性須要-webkit-前綴)
鑑於此,特別注意這個寫法css?-autoprefixer
,具體看-webkit-flex 被移除了
官方介紹的很詳細 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>
見
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 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
安裝npm install husky
的時候會自動往你的git hooks上加代碼,提交代碼的時候觸發想要的npm scripts。
咱們用eslint來作檢測,配置見package.json的npm run precommit
eslint的配置用eslintrc.js
官方推薦的寫法,具體配置弄成一個本身的庫了。
用了eslint推薦的配置再結合eslint-plugin-react的配置
module.exports = { "plugins": [ "gm" ], "extends": ["plugin:gm/recommended"] }
在開發時間避免等後臺api,找了json-server來作api服務,rest風格,很方便。
等後臺ready了,再經過上面提到的server代理調用聯調。
若是你的輸入框比較低的話,鍵盤呼氣就會擋住輸入框。 iphone會自動把input移到可見的位置,而android不會。 能夠在android上對輸入框使用 scrollIntoViewIfNeed 使元素可見。
and在react下,會出現原本點輸入框的,結果倒是點了其餘東西,觸發其餘邏輯了。 因此這裏就搞了500ms的延遲。
在android鍵盤須要用戶觸發才能夠呼氣。iOS 加個autoFocus便可。
一開始是慢慢的算offsetTop,若是層次很深的話,還要算多個parent的offsetTop,而後才能得出,如此必然很煩。 能夠用 getBoundingClientRect 便可。