當代前端應該怎麼寫這個hello world?

發表於2019-01-08

前言

大概16年的時候我們隊react進行了簡單的學習:從DOM操作看Vue&React的前端元件化,順帶補齊React的demo,當時我們只是站在框架角度在學習,隨著近幾年前端的變化,想寫個hello world似乎變得複雜起來,我們今天便一起來看看現代化的前端,應該如何做一個頁面,今天我們學習react首先說一下React的體系圈

無論Vue還是React整個體系圈十分的完備,就一箇中級前端想要提高自己,完全就可以學習其中一個體系,便可以收穫很多東西,從而突破自身

從工程化角度來說,前端腳手架,效能優化,構建等等一系列的工作可以使用webpack處理,這裡又會涉及到SSR相關工作,稍微深入一點便會踏進node的領域,可以越挖越深

從前端框架角度來說,如何使用React這種框架解決大型專案的目錄設計,小專案拆分,程式碼組織,UI元件,專案與專案之間的影響,路由、資料流向等等問題處理完畢便會進步很大一步

從大前端角度來說,使用React處理Native領域的問題,使用React相容小程式的問題,一套程式碼解決多端執行的策略,比如相容微信小程式,隨便某一點都值得我們研究幾個月

從規範來說,我們可以看看React如何組織程式碼的,測試用例怎麼寫,怎麼維護github,怎麼做升級,甚至怎麼寫文件,都是值得學習的

從後期來說,如何在這個體系上做監控、做日誌、做預警,如何讓業務與框架更好的融合都是需要思考的

react體系是非常完善的,他不只是一個框架,而是一個龐大的技術體系,優秀的解決方案,基於此,我們十分有必要基於React或者Vue中的一個進行深入學習

也正是因為這個龐大的體系,反而導致我們有時只是想寫一個hello world,都變得似乎很困難,於是我們今天就先來使用標準的知識寫一個demo試試

文章對應程式碼地址:https://github.com/yexiaochai/react-demo

演示地址:https://yexiaochai.github.io/react-demo/build/index.html

腳手架

現在的框架已經十分完備了,而且把市場教育的很好,一個框架除了輸出原始碼以外,還需要輸出對應腳手架,直接引入框架原始檔的做法已經不合適了,如果我們開發react專案,便可以直接使用框架腳手架建立專案,就react來說,暫時這個腳手架create-react-app比較常用,他有以下特點:

① 基本配置為你寫好了,如果按照規範來可做到零配置

② 繼承了React、JSX、ES6、Flow的支援,這個也是類React框架的標準三件套

③ 因為現在進入了前端編譯時代,伺服器以及熱載入必不可少,一個命令便能執行

首先,我們一個命令安裝依賴:

然後就可以使用腳手架建立專案了:

直接瀏覽器開啟的方法也不適用了,這裡開發環境使用一個node伺服器,執行程式碼執行起來:

系統自動開啟一個頁面,並且會熱更新,看一個專案首先看看其package.json:

所以當我們執行npm run start的時候事實上是執行node_modules/react-script目錄下對應指令碼,可以看到專案目錄本身連webpack的配置檔案都沒有,所有的配置全部在react-scripts中,如果對工程配置有什麼定製化需求,執行

就將node_modules中對應配置拷貝出來了,可隨意修改:

也可以安裝個伺服器,可以直接執行build檔案中的程式碼:

我們的程式碼開始比較簡單,只寫一個hello world就行了,所以把多餘的目錄檔案全部刪除之,修改下index.js程式碼:

這個程式碼不難,我想關鍵是,這個程式碼寫完了,突然就開伺服器了,突然就打包成功了,突然就可以執行了,這個對於一些同學有點玄幻,這裡就有必要說一下這裡的webpack了

webpack

我們說框架的腳手架,其實說白了就是工程化一塊的配置,最初幾年的工程化主要集中在壓縮和優化、到requireJS時代後工程化變得必不可少,當時主要依賴grunt和gulp這類工具,後續為了把重複的工作殺掉工程化就越走越遠了,但是和最初其實變化不大,都是一點一點的將各種優化往上加,加之最近兩年typescript一擊es6新語法需要編譯進行,我們就進入了編譯時代

webpack已經進入了4.X時代,一般一個團隊會有一個同事(可能是架構師)對webpack特別熟悉,將腳手架進行更改後,就可以很長時間不改一下,這個同事有時候主要就做這麼一件事情,所以我們偶爾會稱他為webpack配置工程師,雖然是個笑話,從側門也可以看出,webpack至少不是個很容易學習的東西,造成這個情況的原因還不是其本身有多難,主要是最初文件不行,小夥伴想實現一個功能的時候連去哪裡找外掛,用什麼合適的外掛只能一個個的試,所以文件是工程化中很重要的一環

這裡再簡單介紹下webpack,webpack是現在最常用的JavaScript程式的靜態模組打包器(module bundler),他的特點就是以模組(module)為中心,我們只要給一個入口檔案,他會根據這個入口檔案找到所有的依賴檔案,最後捆綁到一起,這裡盜個圖:

這裡幾個核心概念是:

① 入口 – 指示webpack應該以哪個模組(一般是個js檔案),作為內部依賴圖的開始

② 輸出 – 告訴將打包後的檔案輸出到哪裡,或者檔名是什麼

③ loader – 這個非常關鍵,這個讓webpack能夠去處理那些非JavaScript檔案,或者是自定義檔案,轉換為可用的檔案,比如將jsx轉換為js,將less轉換為css

test就是正則標誌,標識哪些檔案會被處理;use表示用哪個loader

④ 外掛(plugins)

外掛被用於轉換某些型別的模組,適用於的範圍更廣,包括打包優化、壓縮、重新定義環境中的變數等等,這裡舉一個小例子進行說明,react中的jsx這種事實上是瀏覽器直接不能識別的,但是我們卻可以利用webpack將之進行一次編譯:

Hello,Webpack

這裡我們來做個小demo介紹webpack的低階使用,我們先建立一個資料夾webpack-demo,先建立一個檔案src/index.html

然後我們建立一個js檔案src/index.js以及src/data.js以及style.css

這個時候輪到我們的webpack登場,以及會用到的幾個載入器(這裡不講安裝過程):

① webpack-cli是命令列工具,有了他我們就需要在他的規則下寫配置即可,否則我們要自己在node環境寫很多檔案操作的程式碼

② loader結尾的都是檔案載入器,讀取對應的檔案需要對應的載入器,比如你自己定義一個.tpl的檔案,如果沒有現成的loader,你就只能自己寫一個

③ 其中還有個node伺服器,方便我們除錯

因為我們這裡的import是es6語法,瀏覽器不能識別,所以需要安裝babel解析語言:

然後我們在package.json中加入一行程式碼:

這個時候就可以建立webpack檔案了:

然後執行webpack命令便構建好了我們的檔案:

可以看到,只要找到我們的入口檔案index.js,便能輕易的將所有的模組打包成一個檔案,包括樣式檔案,我們關於webpack的介紹到此為止,更詳細的介紹請看這裡:https://juejin.im/entry/5b63eb8bf265da0f98317441

我們腳手架中的webpack配置實現相對比較複雜,我們先學會基本使用,後面點再來怎麼深入這塊,因為現有的配置肯定不能滿足我們專案的需求

頁面實現

這裡為了更多的解決大家工作中會遇到到問題,我們這裡實現兩個頁面:

① 首頁,包括城市列表選擇頁面

② 列表頁面,並且會實現滾動重新整理等效果

頁面大概長這個樣子(因為這個頁面之前我就實現過,所以樣式部分我便直接拿過來使用即可,大家關注邏輯實現即可):

我們這裡先撿硬骨頭坑,直接就來實現這裡的列表頁面,這裡是之前的頁面,大家可以點選對比看看

元件拆分

react兩個核心第一是擺脫dom操作,第二是元件化開發,這兩點在小型專案中意義都不是十分大,只有經歷過多人維護的大專案,其優點才會體現出來,我們這裡第一步當然也是拆分頁面

這裡每一個模組都是一個元件,從通用性來說我們可以將之分為:

① UI元件,與業務無關的元件,只需要填充資料,比如這裡的header元件和日曆元件以及其中的列表模組也可以分離出一個元件,但看業務耦合大不大

② 頁面元件,頁面中的元素

工欲善其事必先利其器,所以我們這裡先來實現幾個元件模組,這裡首先是對於新人比較難啃的日曆模組,我們程式碼過程中也會給大家說目錄該如何劃分

日曆元件

日了元件是相對比較複雜的元件了,單單這個元件又可以分為:

① 月元件,處理月部分

② 日部分,處理日期部分

能夠將這個元件做好,基本對元件系統會有個初步瞭解了,我們這裡首先來實現日曆-日部分,這裡我們為專案建立一個src/ui/calendar目錄,然後建立我們的檔案:

這個時候再執行以下命令便會編譯執行:

雖然不知為什麼,但是我們的程式碼執行了,大概就是這麼一個情況:),接下來我們開始來完善我們的程式碼,日曆元件,我們外層至少得告訴日曆年和月,日曆才好做展示,那麼這裡出現了第一個問題,我們怎麼將屬性資料傳給元件呢?這裡我們來簡單描述下react中的state與props

state是react中的狀態屬性,定義一個正確的狀態是寫元件的第一步,state需要代表元件UI的完整狀態集,任何UI的改變都應該從state體現出來,判斷元件中一個變數是不是該作為state有以下依據:

① 這個變數是否是從父元件獲取,如果是,那麼他應該是一個屬性

② 這個變數是否在元件的整個生命週期不會變化,如果是,那麼他也是個屬性

③ 這個變數是否是通過其他狀態或者屬性計算出來的,如果是,那麼他也不是一個狀態

④ 狀態需要在元件render時候被用到

這裡的主要區別是state是可變的,而props是隻讀的,如果想要改變props,只能通過父元件修改,就本章內容,我們將年月等設定為屬性,這裡先忽略樣式的處理,簡單幾個程式碼,輪廓就出來了,這裡有以下變化:

① 新增common資料夾,放了工具類函式

② 新增static目錄存放css,這裡的css我們後續會做特殊處理,這裡先不深入

於是,我們目錄變成了這樣:

我們將calendar程式碼貼出來看看:

樣式基本出來了:

這個時候我們需要將月元件實現了,這裡貼出來第一階段的完整程式碼:




這段程式碼的效果是:

基礎框架結構出來後,我們就需要一點一點向上面加肉了,首先我們加一個選中日期,需要一點特效,這裡稍微改下程式碼,具體各位去GitHub上面看程式碼了,這段程式碼就不貼出來了,因為我們這裡是寫demo,這個日曆元件功能完成60%即可,不會全部完成,這裡我們做另一個操作,就是在頁面上新增一個上一個月下一個月按鈕,並且點選日曆時候在控制檯將當前日期列印出來即可,這裡是效果圖:

這個時候我們首先為左右兩個按鈕新增事件,這裡更改下程式碼變成了這個樣子,這裡貼出階段程式碼,完整程式碼請大家在git上檢視




至此,我們日曆一塊的基本程式碼完成,完成度應該有60%,我們繼續接下來的元件編寫

header元件

日曆元件結束後,我們來實現另一個UI類元件-header元件,我們這裡實現的header算是比較中規中矩的頭部元件,複雜的情況要考慮hybrid情況,那就會很複雜了,話不多說,我們先在ui目錄下建立一個header目錄,寫下最簡單的程式碼後,我們的index:

然後是我們的header元件:

於是header部分的框架就出來了,這個時候我們來將之加強,這裡也不弄太強,就將後退的事件加上,以及左邊按鈕加上對應的按鈕和事件,這裡改造下index和header程式碼:

就這樣按鈕和點選時候的事件回撥都做好了,這裡圖示有點醜這個事情大家就別關注了,注意這裡是一種規則,設定了規則後按照規則寫程式碼後續會極大提高工作效率,到此我們header部分的程式碼就完成了,很是輕鬆加愉快啊!!!

列表元件

列表元件這裡涉及到部分業務程式碼了,因為存在請求後端資料了,於是我們就比較尷尬了,因為我一點點都不想去為了寫一個demo而去寫建立資料庫或者寫程式碼,於是我們這裡使用mock搞定資料部分,工欲善其事必先利其器,我們這裡首先將資料部分解決掉(PS:因為原來專案的介面不能訪問,所以直接胡亂mock資料,這樣也許會造成之前做的日曆沒有多大的意義,事實上資料應該是用日期引數請求的)

現在想做假資料已經有很多成熟的平臺了,比如這個:https://www.easy-mock.com,使用起來非常簡單,大家去看看他的教程就行,我們這裡直接使用之:

現在訪問這個url就能看到我們的列表資料:https://www.easy-mock.com/mock/5c29d45956db174d47ce162a/example_copy/train/list#!method=get

在react中我們使用fetch獲取資料,這裡直接上程式碼了:

這樣就會將我們的資料列印到控制檯,但是實際專案中我們不會這樣請求資料,而會對他進行兩層封裝,第一層封裝隱藏fetch,讓我們無論是ajax或者fetch都可以,第二層是要給他加上快取功能比如我們的localstorage,包括一些公告引數處理撒的,所以我們會在我們的目錄中新增data目錄專門用來處理資料請求部分,甚至我們會為沒一個資料請求建立一個“實體”,讓各個頁面重複呼叫,我這裡偷懶就直接將之前微信小程式的請求模組和換成模組拿過來使用即可:

 

這裡data目錄是,然後可以看到資料請求成功,並且localstrage中有資料了:

有了資料後,我們來完善我們的列表,因為資料原因,我們這裡便不做滾動分頁功能了,一般來說列表類元件特點還是比較突出的:需要提供一個資料請求模組以及一個資料處理器,最後加一個模板就可以完成所有功能了,這裡還是先來實現列表部分程式碼,這個列表元件因為涉及的業務比較多而且每個頁面的列表變化也比較大,我們暫且將之放到ui目錄,後續看看這塊怎麼處理一下,我們依然先在這裡建立list目錄:

這樣一來,我們輕易的就將頁面做出來了:

接下來我們使用元件完成其功能,這裡我們將程式碼做一層分離,將列表元件分成兩部分,第一部分是不變放在UI中的部分,另一部分是我們要求傳入的模板元件,因為每個頁面的列表展示都是不一樣的,於是我們先實現外層列表,這裡就相當於要傳遞一個元件給另一個元件使用,我們簡單的嘗試了下可行性:

證明是可行的,其實React早就知道我們有這種騷操作,所以衍生了高階元件的概率,這裡我們簡單介紹下

PS:大家可以看到,我們文中的例子都不是生拉硬套的要應用某個知識點是確實有這種需求

高階元件-繼承的應用

參考:https://github.com/sunyongjian/blog/issues/25

高階元件只是名字比較高階罷了,其實跟我們上面程式碼的例子差不多,每個React元件事實上都是一個js物件,我們可以例項化一下他,完成任何騷操作,但是出於規範化和程式碼可控(在不非常熟悉底層程式碼的時候,隨意使用騷操作,可能會出莫名其妙的BUG,但是也是因為莫名其妙的BUG會導致你更熟悉框架,BUG帶來的框架理解有時候優於機械原始碼閱讀,所以在非核心專案上,我們非常建議你騷操作)

上面的說法有點不好理解,這裡換個方式說,所謂高階元件,就是我們有一個元件,這個時候我們會給他傳遞各種引數,其中一個引數是另一個React元件,並且我們需要在父元件中使用他:

這個例子依舊不夠清晰,我們再舉個例子:

這裡會輸出(這裡說爸爸可能不太合適,這裡應該是個組合關係):

這裡核心概念還是這裡使用了一個繼承解決這個問題:

所以,高階元件其實並不神祕,就是實現了一個用於繼承的元件,然後在子元件裡面做業務性操作,在之前屬於非常常規的操作,這裡推薦看一點老一點的東西,脫離框架的東西,類比幫助大家瞭解高階元件:https://www.cnblogs.com/yexiaochai/p/3888373.html,於是這裡我們稍微改造下我們的list元件的框架結構:

PS:這裡一定要注意,一個專案或者幾個專案中,列表的大體HTML結構一定是非常一致的,這裡是個規則約定,規則先與程式碼,先於框架

由此,基本框架就出來了:

我們這裡繼續完善這個元件即可,這裡具體程式碼各位github上看吧:https://github.com/yexiaochai/react-demo

PS:事實上,我們index.js裡面程式碼已經很多了,應該分離開,但是我們程式碼已經接近尾聲就懶得分離了,大家實際工作中一定要分離

我們程式碼稍作改造後就變成了這個樣子(由於只是demo,對於一些需要計算展示比如篩選硬座票數等未做實現):

至此,我們的demo就結束了,如果有必要可以新增各種篩選條件,比如這裡的排序:

比如這裡的篩選:

但是我們這裡由於是簡單的demo加之本篇部落格篇幅已經很長了,我們這裡就不做實現了,反正也是運算元據,就此,我們業務部分程式碼結束了,接下來我們來做一點工程化的操作

元件樣式問題

可以看到,之前我們的元件樣式,全部被我們柔和到了global.css或者index.css中了,對於有些工廠作業做的很好的公司,會具體分出重構工程師(寫css的)和程式工程師(寫js的)兩個崗位,一般是重構同事將css直接交給js同事,這樣做起來效率會很高,所以多數情況下,我們全域性會有一個樣式檔案,業務頁面會有一個樣式檔案,這其實沒什麼大問題,可能出現的問題請大家閱讀下這篇文章:【前端優化之拆分CSS】前端三劍客的分分合合,這裡其實已經涉及到了一個工作習慣他要求我們做頁面的時候就分成模組,做模組的時候要考慮模組的css,這樣做也會有一個弊端就是全域性性的東西就比較難過了,所以一個大專案的樣式相關工作最好由一個資深一點的同事設計規則和公共的點,其次不然很容易各自為戰,我們這裡完成一個簡單的工作,將列表部分的程式碼從global中分離出來,我們先找到對應的樣式程式碼:

新建一個style.css暫且放到ui/list目錄中,其實這個list的樣式跟業務程式碼更有關係,放裡面不合適,但是我們這裡做demo就無所謂了,這裡分離出來後稍作改造即可:

這裡未做高階使用,關於高階的用法,我們後續有機會再介紹,接下來就是部署以及工程化相關工作了,考慮篇幅,我們後續再繼續

結語

本文程式碼地址:https://github.com/yexiaochai/react-demo

演示地址:https://yexiaochai.github.io/react-demo/build/index.html

可以看到,從元件化一塊的設計,React是做的十分好的,我們沒花什麼時間就把一個簡單的頁面搭建了出來,實際專案過程中正確的使用React會有很高的效率;另一方面,webpack一塊的配置,create-react-app已經完全幫我們做完了,我們只需要按照他的規則來即可,這個黑匣子裡面的東西又非常多,我們後續根據實際的專案再深入瞭解吧,一時之間也說不完,後續我們繼續研究如何使用這套程式碼相容小程式開發,以及一些工程化問題

相關文章