基於React和Webpack的Optimize小技巧

公司項目採用使用React16+Webpack3+Graphql來做爲技術構建,在圖像等方面上使用七牛;
下面是本人將會圍繞當前技術來進行優化的體驗,理解和使用到的都不算特別複雜,可是點比較多,可能能夠啓發一下;javascript


React

版本升級(當前是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等,減小體積;
六、一切須要使用的依賴都考慮小而優的,如

  1. 日期方面能夠採用date-fns;
  2. 輪播使用react-id-swiper來代替swiper;
  3. 視頻採起lottie-web庫(lottie_light);

Webpack

版本升級(當前是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便可;
相關文章
相關標籤/搜索