React學習心得淺談
文章目錄
React學習淺談(1)-技術棧
這兩天花了點時間學習了下React,本人並不是一名純前端研發人員,之所以想學習React只是想補全自己的技術棧。之前一直都是使用jquery
+bootstrap
來開發頁面,其實大多數情況下這種技術棧也夠了。但是現在都流行前後端分離,所以諸如React和Vue這類MVVM前端框架才會大行其道。
這所以寫這篇文章,主要還是為了對自己這兩天的學習做個總結,免得後面遺忘。同時,也希望能給那些想學習React卻比較迷茫的同行們來個拋磚引玉,說下我個人的學習路線。
我覺得React的優點在於元件化以及JSX語法。元件化實現了頁面通用元素的封裝,提高頁面元素的複用性;而JSX語法則便於我們在js中編寫html程式碼。
1. React技術棧
學習React是有一定的學習成本的,主要是如果想要用它進行專案開發,就需要學習一系列它的技術棧,包括基本知識、執行編譯環境和一系列外掛。而我也只是學了個冰山一角。
1.1. 執行編譯環境
我採用的nodejs+npm+yarn+webpack。
-
Nodes:javascript執行環境,我們編寫的程式碼需要在nodejs上執行。
-
npm:在安裝完nodejs後,預設就已經按轉了npm了。npm是包管理軟體,能夠快速地基於命令列的方式安裝各種組建包,並對組建包進行管理。例如:
npm install -g create-react-app --save-dev
-
Yarn:yarn和npm功能類似,都是對包進行管理。yarn具有快取包的功能,下載過一次,下次安裝可以直接從本地進行安裝。
yarn add react-redux
-
Webpack:打包工具,用於將javascript進行打包。
1.2. ES6
要學習並使用react,ES6是必須要學習的。在react開發過程中,會大量地使用到ES6中的各種特性。諸如:
- class類:例如
class InputComponent extends React.Component
; - let/const:定義變數、函式會大量使用到let和const,而不會再去使用var;
- import/export:需要使用import引入元件,並將自己寫的元件通過export輸出,方便其他元件引用;
- 模板字串:便於編寫字串,不需要通過
+
來組裝字串。 - Object.assign():用於將兩個物件進行合併。
還有其他很多特性會用到,所以對ES6的學習非常重要。
1.3. React
React是基於元件化的思想進行開發的js框架,所以我們需要有元件化的思想。學習React主要會用到:
- jsx語法:通過該語法方便在js中編寫html程式碼;只能有一個頂級元素!
- React.Component:這是React元件的基類,所以編寫的React元件都要繼承這個類。元件之間的引數的傳遞採用
this.props
進行傳遞。 - ReactDOM:用於將元件渲染到頁面上。
1.4 Redux
Redux用於對JavaScript的狀態進行管理,通過Redux,可以有效銜接頁面操作和操作完成後的狀態之間的關係,以及基於雙向繫結實現狀態對監聽狀態變化的監聽器的影響。所有的狀態資料儲存在同一個Store中。
其中一個詞:狀態,很重要。我們在使用Redux,在動作產生後(例如頁面的一個點選事件),那麼傳遞給狀態的不是對事件的處理動作,而是事件完成後的狀態。例如點選登陸按鈕進行登入,狀態不是執行動作的事件,而是動作完成後的狀態:使用者名稱密碼是什麼?驗證是否通過?
所以Redux會涉及到四個概念:
-
Action:該動作不是點選事件的動作,而是點選之前或者點選之後設定狀態的動作。例如:
const loginReceived = (checked)=>{ type:'login_received', checked }
從上面可以看出,我們傳遞的不是事件,而是是否驗證通過這個狀態。
-
Reduce:用於接受action產生的狀態,並對store中的狀態進行修改。所以reduce會在建立store時作為引數傳進去,一旦有action被dispatch到store中,store就會呼叫reduce進行處理。Reduce是一個純函式。並且只能有一個。多個Reduce通過
combineReducers
進行組合。 -
Dispatch:動作分發,將動作分發到store中。
-
Store:用於儲存狀態State。
1.5 Middleware
那麼既然用於傳遞的是使用者名稱、密碼、是否通過,那麼“驗證”事件什麼時候執行呢?理論上應該是在狀態——獲取到是否通過——之前:動作—>驗證—>狀態。
也就是說“驗證”這一步是發生在Action發生之後,Reduce之前。這裡就涉及到middleware
元件。middleware是一個概念,類似於攔截器,用於攔截每一個dispatch到store中的action,在action發生之前和發生之後進行攔截處理。
例如記錄日誌,可以使用createLogs
,上面說的中間處理,可以使用redux-thunk
。
2. 環境搭建
環境搭建包括開發環境和編譯環境。
2.1 搭建開發環境
我主要是用VS Code進行開發,優點不多說,絕對好用就是了。需要安裝一些外掛才能發揮更強大的作用。我裝的外掛如下圖所示:
2.2 搭建編譯環境
-
安裝nodejs。這個可以直接下載安裝包進行安裝,安裝完成後,也就支援npm了。
-
安裝yarn。windows平臺下下載安裝包安裝,mac可以使用homebrew進行安裝。
brew install yarn
-
切換淘寶映象:
npm config set registry https://registry.npm.taobao.org
-
安裝cnpm
npm install -g cnpm
-
安裝react開發環境建立元件。
npm install -g create-react-app
以後可以直接使用
create-react-app projectname
來建立開發環境,會預設初始化好開發環境需要的基本依賴。
2.3 搭建完整的專案開發環境
接下來介紹如何搭建一個完整的專案開發環境。例如專案名稱是一個天氣查詢專案,展示當前的天氣。那麼我們可以在命令列下做如下操作:
cd Documents/projects/
create-react-app weather
等待專案初始化環境建立完成後,可以通過yarn安裝其他以來包:
yarn add redux
yarn add react-redux
yarn add redux-logger
yarn add redux-thunk
yarn add cross-fetch
如果需要其他依賴包,也可以這樣安裝即可。
3. 編碼設計
我們就以編寫一個獲取天氣的簡單小專案來上手。
3.1 建立專案目錄
預設我們在src
目錄下建立四個子目錄:
actions
:用於存放action的js檔案。再次記住:action不是事件函式,是傳遞狀態state的修改值的函式。reduces
:用於存放reduce的js檔案。containers
:用於存放將state、dispatch方法與有狀態元件(也就是用於最後渲染介面的元件)進行連線的函式。components
:用於存放無狀態元件和有狀態元件的函式。- 無狀態元件:純元件,不關心state,只根據傳遞的props編寫html元素的元件。例如一個input或者button元件,而元件中的動作也會通過引數觸發有狀態元件中的函式,從而實現對狀態的修改。
- 有狀態元件:需要關心和設定state,可能會包含多個無狀態元件。最終會通過
ReactDOM.render
渲染成頁面的元件。
可能我們還會建立utils
目錄或者其他目錄。最後,還有一個最外層的index.js
檔案,我們一般在這裡建立store,並渲染頁面。
3.2 編寫action
編寫action,我們需要分析頁面獲取天氣會產生幾個事件。頁面的功能是:“根據選擇的不同地市,獲取該地市的天氣,將獲取到的地市展示在介面上“。根據這句話,我們來分析有哪些action。
- 選擇不同的地市:”選擇“是事件,也就是
onChange
或者onClick
事件。選擇的“地市”就是狀態值。所以我們會建一個selectedCity(cityCode)
的函式。注意方法名是selected
,而不是select
,用的是過去式,表示被選擇的,是一種狀態——天氣“待獲取”。 - 獲取該地市的天氣:從字面上看,應該是發起ajax請求獲取天氣。但是預設的action是不能傳送ajax請求的,只傳遞狀態。這裡傳遞什麼狀態?那就是天氣“獲取中”,所以我們會建一個
requestWeather(cityCode)
的函式。那ajax在哪兒發起呢?會用到前面說的redux-thunk
來發起。 - 將獲取到的天氣展示在介面上:自然而然,我們會看到,這裡的狀態是“已獲取”到天氣,那麼我們傳遞的窗臺值就是獲取到的天氣資訊,可以是json。所以我們會建立一個
receivedWeather(cityCode,json)
的函式。 - 最後就是ajax請求函式。該函式通過
redux-thunk
來編寫,同時會呼叫requestWeather(cityCode)
和receivedWeather(cityCode,json)
函式,來完成獲取天氣之前的準備動作(例如彈出轉圈等待)和獲取到天氣之後的動作(例如渲染到頁面)。所以我們會建立一個fetchWeather(cityCode)
函式。
3.3 編寫reduces
因為reduce是用於修改state的,並且是一個純函式。那麼首先第一步,也是最重要的就是想想看我們的state長什麼樣子?也就是什麼樣的資料結構(json結構)。
{
selectedCity:'xxx', //選擇的地市
weatherInfo:{//天氣資訊,是一個json
},
isFetching:true/false //是否獲取中,如果是ajax請求中,則是true,否則是false。
}
想好了state長什麼樣子,就要考慮編寫幾個reduce函式呢?我這裡有個個人看法,就是看state裡有幾個頂級的key,就寫幾個函式。例如上面有selectedCity
、weatherInfo
、isFetching
三個頂級key,那麼我們就建立三個同名的函式。為什麼要這樣呢?一是為了方法的獨立性,便於方法重用;二是正好基於combineReduces
函式,在整合這三個reduce函式後,就會生成如上的資料結構。
既然是寫三個函式,同時也說了這樣可以保證方法的獨立性。那麼每個函式返回的state也需要相應的只返回對應的獨立的結果。例如selectedCity
函式返回的state就只是一個字串。是不是很獨立呢?
3.4 編寫components
編寫components,就需要考慮:
- 頁面長什麼樣子,哪些頁面元素是無狀態元件,哪些是有狀態元件;
select
元件是無狀態元件weatherApp
是有狀態元件,裡面包含select元件。
- 在編寫元件的時候,需要考慮state裡有什麼元素,哪些元素是元件需要用到的;
select
元件會用到selectedCity
的值;weatherApp
會用到weatherInfo
的值;同時還會根據isFetching
的值顯示“載入中…“。
- 還要考慮元件觸發的事件( `onClick``)會呼叫哪個action。
select
元件的onChange事件會觸發selectedCity
函式;weatherApp
的componentWillReceiveProps()
方法會觸發fetchWeather
函式,用於監聽一旦selectedCity
的值發生變化,就獲取天氣。
3.5 編寫containers
containers的寫法一般是固定的,就三個作用:
- 將state的值傳遞給元件的props,我們會建立
mapStateToProps(state)
方法;(當然也可以不寫這個函式,那就是將state作為props的一部分傳遞給元件) - 將dispatch各個action的函式傳遞給元件的props,方便業務呼叫(當然也可以直接傳dispatch作為props的一部分),我們會建立
mapDispatchToProps(dispatch)
方法; - 呼叫
connect
方法,將元件與redux連線起來,並將上面的兩個方法作為connect的引數。
經過上面的分析,我們就可以編寫程式碼了,分別在對應的目錄下建立js檔案,並在js檔案中建立對應的方法。