距離我進新公司也有一個多月,這一個月的事件使用react寫了一個項目,期間斷斷續續重構了兩三次,目前已經完成第一階段測試,也總結分享一些使用react的一些坑。css
先囉嗦幾句講一下react原理,新人能夠認真看下,老鳥可跳過。前端
react並無像其餘如vue,ng同樣採用MVVM模式,所謂MVVM模式,狹義來講就是將模板與數據綁定在一塊兒,當數據發生改變時,模板自動更新,這是中間的VM,最左邊的M能夠理解爲咱們看到的頁面,而最右邊的M能夠理解爲原始數據(例如數據庫數據)。
其實要知道,這些框架模式歸根結底的目的但願使代碼更容易開發和維護。當你寫一個小頁面你不以爲什麼,可是當你的頁面愈來愈龐大,愈來愈複雜,開發人員走了一批又一批的時候,你就會明白了。而如何解決,如今比較公認的理念一個是組件化,將頁面拆分紅一個個組件,其實拆分紅組件的目的並不全是爲了複用,我以爲更可能是爲了維護;一個就是但願讓應用層的編程能更專一於業務邏輯,那麼這些框架都去作了處理,減小了大量DOM操做,讓業務開發更加專一。vue
那麼咱們看看react採用的是什麼原理。其實react採用的方法簡單粗暴:它並無對模板作數據綁定,而是每當數據變化時,就從新渲染模板。這有一個很大的好處就是每當數據變化時,對頁面來講只有一次IO操做,而單純的雙向綁定更新DOM會有不少次;但有一個問題,若是隻改變了一個dom的數據,整個模板都會從新渲染。那react解決的方法是每當數據改變時,就進行對比。react
那麼該如何對比呢,最簡單的方法是每當數據改變,就去頁面獲取相應的DOM信息,而後與如今的DOM信息作比較。這個方法有個致命的缺點就是每次有DOM改變,就會有許多讀取操做,IO操做太多,很影響性能。那麼能夠經過空間換時間的方法,將DOM信息保存起來,就避免了去頁面獲取信息的IO操做。那麼咱們看看一個真實DOM有多少數據webpack
若是咱們把全部原生DOM緩存起來進行比較顯然內存會爆炸,而咱們所須要的僅僅是幾個爲數很少的狀態信息(例如style啊這些),這時虛擬DOM應運而生,若是說原生DOM是一塊豬肉,那麼虛擬DOM就是這塊豬肉中多精肉,他剔除了那些對咱們來講沒有太多意義相反還佔內存的狀態信息,而只將咱們所須要的內容留了下來。那虛擬DOM該如何比較呢,就涉及到了虛擬DOM的diff算法。git
簡單來講兩個模板就像兩棵樹同樣,傳統的樹對比的時間複雜度是O^3,也就是說要整棵樹遍歷三次,那react根據DOM的特色:跨層級的操做較少。什麼叫跨層級,舉個例子一個組件有三個層級關係(嵌套三層),把第二層的div放到第三層就屬於跨層級操做。這種操做其實仍是比較少的,react官方也不推薦這麼寫。那麼利用這個特色,react只diff同層級的DOM。這裏涉及如下幾種狀況github
tag變化(標籤變化)web
屬性變化算法
第二種沒什麼好說,就是進行同層級對比。這裏詳細說一下第一種變化,react的方法是當前層級往下所有刪除替換,簡單暴力。在業務開發來看,你同層級類型都不一樣了,好比div變成了input,那麼你的子組件相同的概率也較小,所以不如整個替換簡單暴力。同時這也說明爲何列表須要key屬性,由於列表不少的刪除操做對於react來講是不知道的,它須要一個key來了解到底誰是誰。數據庫
做爲前端,拿到原型第一件事就是要與你的產品充分溝通,評估該項目是否須要引入redux,那麼如何肯定須要引入redux呢,這邊有幾點:
頁面之間組件之間通訊較多,且是跨層級的;
頁面的交互邏輯較複雜,且常常引發多處組件變化。
再而後就是對state的設計。對於後臺的返回的數據,你並不知道到底哪些是有用的,哪些可能如今沒用之後有用,所以個人建議是對於每一個api都將它存在一個object裏。那麼組件該如何去獲取,首先不能所有經過頂部container獲取依次往下傳,也不能粒度很細的去一個個connect,個人建議是對於一個object,能夠用一個container去connect,粒度把握主要看你的業務需求。
還有一個要不要全局都使用redux。個人觀點是否認的,我認爲對於局部一個組件內的狀態徹底能夠經過setState來知足。
首先將圖片作一些劃分。例如以500k做爲分界,小於500k爲小圖片,不然是大圖片。對於小圖片,咱們須要作以下判斷:
頁面是否重複使用?是就用雪碧圖,不然轉base64.
對於大圖片,能夠進行壓縮後使用。
base64能夠用webpack的url-loader替換。
舉個例子
require('url?limit=250!./xxx.png') //這裏就會使用url-loader,假如圖片小於250,就會轉爲base64
對於適配,我所知比較好的方法是利用rem做爲單位,將頁面寬度等分紅10個rem,根據頁面動態的用js去改變font-size,達到適配不一樣瀏覽器的目的。例如愛瘋寬320px,那麼font-size設置爲32px。那麼10rem就是等於整個屏幕的寬度。可是有一個特例就是高清屏,通常高清屏的物理像素是實際像素的2倍,那麼當你想顯示一個寬度爲1的邊框時,在普通屏幕是1px,在高清屏能夠有0.5px(問題是不少瀏覽器不支持,爲將0.5px認爲是0)。雖然都使用1px在二者屏幕上其實是同樣的,可是高清屏裏的1px在射雞師眼裏是沒法達到他對於1的要求的。因而就有一些解決方案,比較簡單是是使用transform:scale(0.5)。那麼還有一種解決方案就是阿里的移動端解決方案,原理是將頁面總體scale縮小,而後放大font-size,來保證rem爲單位的佈局不變,可是px爲單位的會被縮小。
首先先肯定需求,確實有這個需求的時候再談。
webpack其實會幫咱們作第三方依賴的懶加載處理,那麼針對react,咱們能夠經過現成的庫來實現懶加載react-lazyload,或者使用webpack現成的
require.ensure([],()=>{ require('public.js') })
來實現。
其實這個鉤子能夠極大的幫助咱們去提高性能,因爲它的存在,咱們能夠本身判斷哪些是咱們組件須要的state,哪些是不須要的,那麼這就能夠阻止react進行沒必要要diff。可是有一個問題就是對於對象咱們很難去判斷他們是否相等,那麼能夠經過immutableJs的fromJS和is方法來解決這個問題。其實immutableJs的好處遠不止於此,目前我也尚在填坑中。
使用不可變數據,能夠更好的達到函數式編程,不只利於單元測試,也更有利於後期維護整個大的state。由於他的不可變特色,咱們不會在不經意見不當心改變了state,而引發沒必要要的問題。
爲了使組件中的css做用域相互獨立,通常採用Css Module
,那麼爲了使組件看上去更像組件,而且易於後期維護,通常咱們會這樣結構化組件文件:
那麼對於每個初始的jsx,咱們大多會這樣初始化
import s from './App.scss' import{Component} from 'react';//獲得組件方法 class App extends Component{ render(){ return ( <div className={s.container}> </div> ) } } export default App;
不難發現,對於每個組件,我都須要去手動的建立這些文件和文件夾,而這些操做實際上是重複且無心義的勞動,因而我造了一個小輪子,一個命令行小工具,來解決這個痛點。
react-component-maker,歡迎猛戳點star!
困了,本寶寶要睡覺了,還有的內容下次再說吧,再見。