公司項目採用使用React16+Webpack3+Graphql來做爲技術構建,在圖像等方面上使用七牛;
下面是本人將會圍繞當前技術來進行優化的體驗,理解和使用到的都不算特別複雜,可是點比較多,可能能夠啓發一下;javascript
版本升級(當前是16.8.6)html
若是是React15的更應該升級到16,除新的Api外,React自己也進行了優化如Fiber等,體積也更小;java
Api更新node
一、 React.Memo:LessState組件上採用React.Memo來進行處理,代替原先的PureComponent;
二、 去除依賴庫:若是原先有使用一些Lazy庫,能夠考慮直接使用React.Lazy來實現,減小打包體積,原先的路由懶加載是直接寫了一個方法,也可使用React.Lazy來完成而且Suspense能夠實現佔位圖;react
沒用React.Lazy前的寫法 import React, { Component } from 'react' import LoadingViewContainer from '../components/LoadingViewContainer' export default function asyncComponent(importComponent) { return class extends Component { state = { component: null } async componentDidMount() { const { default: component } = await importComponent() this.setState({ component: component }) } render() { const C = this.state.component return C ? <C {...this.props} /> : <LoadingViewContainer /> } } }
三、 使用Hooks:Hooks是React16.8以後出的一個新的Api,與之前的Class Component改變不少,如useReducer有人用來實現Redux,至因而否能夠真的代替,這個尚未深刻了解,按官方說法,由於不使用原先生命週期以及邏輯業務的複用性,能夠減小不少代碼;具體的不在這裏去詳寫,自己也理解不夠透徹,只貼一個本身寫的簡單的代替原先React-Helmet(Helmet),後續可能會單獨寫一下Hooks;webpack
import { useEffect } from 'react' function Helmet({ title, link }){ useEffect(() => { document.title = title const node = document.getElementsByTagName('link') let isHadLink = false for (let i = 0; i < node.length; i++) { // NOTE:有link直接修改便可 if (node[i].rel === linkRel) { isHadLink = true node[i].href = link break } } if (!isHadLink) { const newLink = document.createElement('link') newLink.rel = linkRel newLink.href = link document.head.appendChild(newLink) } }, [title, link]) return null }
四、使用Persistweb
若是有使用redux,建議加上redux-persist,若是是其餘的框架應該也有相對應的persist persist會將該redux的reducer(可加入白名單和黑名單,只保存指定reducer)存到localstorage裏面 在用戶後續打開應用的時候會直接獲取localstorage裏面的數據去生成reducer,在用戶體驗上有提高;
五、用法npm
1. function的bind寫在constructor,不要寫在render裏面,或者建議直接在建立的時候使用 handleClick = () => { dosomething } 2.在取值的時候不要給元素加data-xxx={xxx},而後用e.target去獲取改屬性值 handleClick = e => { e.target.xxx // bad } <div data-value={value} onClick={this.handleClick} /> 能夠直接return一個function來處理 handleClick = value => () => { value } <div onClick={this.handleClick(value)} /> 3.不要在render裏面定義常量,減小在render的邏輯 render函數是渲染界面用的,一些常量和邏輯儘量放到constructor等地方,避免在組件update時重複建立常量; 4.避免傳遞過多props 減小<component {...this.props} />,加劇了shouldComponentUpdate裏面的數據比較;
六、延遲加載外部JSjson
必需要使用的依賴庫,可經過webpack打包進去,但一些第三方的統計、地圖等,能夠在須要用到的場景,再調用方法進行加載; 或者該依賴庫在npm上有,也能夠npm install進去用webpack分包;
export default function loadJs(url, loadSuccess) { if (!url) { return null } let script = document.createElement('script') script.type = 'text/javascript' if (script.readyState) { script.onreadystatechange = () => { const state = script.readyStat if (state === 'loaded' || state === 'complete') { script.onreadystatechange = null loadSuccess && loadSuccess() } } } else { script.onload = () => { loadSuccess && loadSuccess() } } script.src = url document.body.appendChild(script) }
經驗技巧redux
一、 圖片在須要用到的地方require,不要在文件開頭直接import進來;
二、 使用import { xxx } from 'xxx',避免import整個文件,注重導包;
三、 一些必需要的依賴能夠將它放到須要觸發的條件下import,如項目用到的驗證碼驗證,因此將下面代碼放到Click裏面進行處理;
handleClick = () => { import('hash.js/lib/hash/sha/256').then(({ default: sha256 }) => { //do something }) }
四、 在同級元素顯示可使用<></>來包裹,<React.Fragment>也是和<>同樣,可不渲染該標籤,以下面則不會出現<div>;
<div> <a /> <b /> </div> 能夠採用 return ( <> <a /> <b /> </> ) 或者 return [ <a key="a"/>, <b key="b" /> ]
五、動畫方面採起json來實現,不使用mp4等,減小體積;
六、一切須要使用的依賴都考慮小而優的,如
版本升級(當前是4.32.2)
webpack4在打包上升級了很多,若是是使用creat-react-app的,直接使用腳手架的config便可,直接會減小打包的體積;
一、瀏覽器語法兼容
使用polyfill.io來處理語法兼容,再也不引入core-js、object-assign、promise、raf、whatwg-fetch; 直接在html文件上加載該文件便可,它會直接根據瀏覽器的UA進行判斷下載須要用到的兼容補丁;
二、使用的第三方庫按需加載來減小打包體積
如說提到的date-fns,babel-plugin-date-fns在webpack的配置中 { test: /\.(js|mjs|jsx|ts|tsx)$/, include: paths.appSrc, loader: require.resolve('babel-loader'), options: { customize: require.resolve('babel-preset-react-app/webpack-overrides'), plugins: [ [require.resolve('babel-plugin-date-fns')], xxxxplugins ], cacheDirectory: true, cacheCompression: isEnvProduction, compact: isEnvProduction } } 在代碼中import { format } from 'date-fns',不直接import dateFns from 'date-fns', 同理如lodash、swiper等第三方庫一樣能夠進行這樣處理;
三、圖片處理
1:webpack的config { test: [ /\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.svg$/, /\.(eot|ttf|woff|woff2|otf)$/ ], loader: require.resolve('url-loader'), options: { limit: 100, //注意這個limit限制,不要設置太大,容易把大圖打包進去js裏面 name: 'static/media/[name].[hash:8].[ext]' } } 2:圖片格式 圖片採起了webp格式,部分圖片直接使用七牛的api進行切割等,減小加載的體積; 3:Icon複用 可使用一些Icon庫構建UI,若是公司有總體Icon要求,建議處理好Icon的分類和組件,避免屢次加載相同的Icon; 4:CDN 將圖片以及CSS和JS走CDN,能夠加快加載速度;
四、引入過量
在Home(首頁的container)裏面,咱們常常會import Actions(所有的action),而Actions可能又包含了不少的query(如graphql的query字符串),但在首頁其實並不須要加載所有的actions,對於一些只在某些頁面會調用的action(如加載數據)能夠進行分離,不放入到actions裏面,actions裏面只保留多處會進行調用的action,特有的直接該頁面import XXXActions便可;