在 2017 年學習 React + Redux 的一些建議(上篇)

發表於2017-09-11

 

68747470733a2f2f7777772e726f62696e776965727563682e64652f696d672f706f7374732f746970732d746f2d6c6561726e2d72656163742d72656475782f62616e6e65722e6a7067

使用 React + Redux 這個技術棧開發應用已經有很長一段時間了,我的一些使用經驗也許會有些主觀,但我覺得寫出來也許對你開始學習或是進階使用 React + Redux 會有些幫助。Redux 並不是只和 React 結合使用的,它也可以和其他的很多類庫結合起來一起使用,即使你還未開始深入使用,你也可以閱讀文中的部分內容。同時,如果你有一些建議或是疑惑,可以在 Github 給我提交 Issue,很樂意與你一起交流。

[TOC]

對學習 React 的一些建議

在深入 Redux 、Testing 或是其他更高階的使用之前,我們還是先開始 React 吧。

不要太過在意腳手架

你已經準備好開始學習 React 了嗎,我建議你不要一開始就進入到選擇和學習專案腳手架的困擾中,因為你一上來就得接觸Webpack、Babel、Testing Tool等,實在是眼花繚亂。

我建議你可以首先採用 create-react-app 這個工具,他是Facebook For React 官方提供的零配置CLI 命令列工具。從技術上來說雖然它依然是一個腳手架,但是它遮蔽了所有的工具配置,你可以用它來快速生成一個React專案所需的基本工程。

僅僅以上幾步,你就可以在啟動開發了,非常的快吧。

但是等你想深入專案的工程化配置而不再想使用 create-react-app 的時候,那麼,是時候該去學習一個適合你的構建工具了。在使用 create-react-app 這個工具的時候,它讓你快速開發的同時也讓你錯過了如何真正的使用工具並去配置工具。

當你從零開始搭建一個你自己的專案工程的時候,那麼你將需要從底層來了解這些技術是如何工作的,這樣的話,慢慢就能產出一個你自己的專案腳手架了,在團隊裡面去推廣使用。

小結:

  • 避免開始學習的時候就去使用腳手架
  • 使用 create-react-app 去學習 react
  • 當你熟悉 react之後
    • 去探索工具本身如何使用
    • 建立屬於你自己的專案腳手架

在你學習 Y 的時候要先去學習 X

雖然學習 React 不難,因為它僅僅是個 view library,但是 React 的整個生態鏈非常豐富,並且會有很多關於如何學習的方法和資料。

而我的建議是,在你學習東西的時候需要學習這個技術的前置技術,否則學習起來會很吃力。所以你在開始學習這個技術棧的其他東西之前,下面所列舉的內容應該會對你很有幫助:

  • JSX 語法
  • ReactDOM.render
  • 使用 setState 來改變元件的狀態 state
  • 元件生命週期相關的方法
  • 事件和表單
  • 幾種建立元件的方式
  • 複合元件 composeable
  • 高階元件的使用和定義 HOC

一般建議你在開始下一部分內容之前,你可以先把這些 React 相關的內容都學習完成。

什麼時候引入 Redux

在你遇到應用的狀態管理問題之前,你可以通過擴充套件應用的方式來解決,或是你在你的應用中壓根就沒遇到過這樣的問題,因為你可以使用 setState 來很好的管理你的應用。但其實 setState 也不是那麼高效,畢竟它也不是萬能的。也許你會發現你已經在忙於處理太多的元件內部狀態,那麼,該是時候引入類似 Redux 等狀態管理庫了,不過有幾個事情需要注意:

  • 在學習 Redux 前得先學好 React
  • 可以閱讀以下You might not need Redux
  • 不是所有的狀態都需要放在 Redux 的 Store 中,也不能完全取代 setState

那關於 ES6 呢

大量的關於React的示例都採用ES6語法,也許你在其他的專案中已經學習並使用了 ES6 相關的語法和API,或者也許你還沒接觸呢。不過,ES6對於React也不是必須的,我的一些建議是:

  • 如果你有使用類似 angular 等前端框架或是類庫的經驗
    • 你可以在你熟悉的環境裡面去學習 ES6
  • 如果你是前端入門的新人
    • 你可以在React中繼續使用ES5的語法和API
    • 或者在你學習React之前,先學習一下ES6
  • 如果你是個前端老司機
    • 逐步在React應用中使用ES6吧

我比較建議的學習方式是,學一個東西之前一定要先掌握它相關的前置知識,另外,也一定要記住:不要一次性學習所有東西,不然反而啥都掌握不了。

宣告式的React元件

一般地,會有三種不同的方式來宣告一個元件:

  • React.createClass 使用這個API來定義元件
  • React ES6 class components 使用 ES6 的class 來定義元件
  • Functional stateless components 通過函式直接定義無狀態元件

那什麼時候該用什麼方式來定義呢

無狀態元件:適合用來宣告沒有元件生命週期方法並且沒有內部狀態的元件。這種寫法很簡單,就是一個純函式,一個狀態輸入,輸出就是elements。

這是一種最輕便最高效的元件宣告方式,這種元件沒有任何的內部狀態,使用的時候也無法訪問到元件的屬性,所以一般建議能用這種方式宣告元件的時候就儘量採用這種方式。

如果你需要使用元件生命週期方法,並且需要去處理元件內部狀態(this.state) ,或者需要獲取這個元件(this.ref)。那麼,這個時候建議你使用ES6的 class 來宣告元件。

另外,建議還是別用React.createClass這種方式宣告元件了,Facebook 官方在React V0.13版本的時候就說過,以後的目標是使用ES6 classes的方式來定義,會完全廢棄React.createClass

另外,這有兩篇博文也推薦給你看:

輕量級的函式式無狀態元件

專案中一定需要去宣告很多元件,我們可以一起來完成一個 TodoList 元件:

我們還可以按函式的方式將其拆分

這個例子有些簡單,無法很直接的看到這種定義方式的好處,但是當我們將元件拆分後將更具有可讀性、可複用性以及可維護性。這種方式很靈活,而且很輕鬆就可以宣告多個元件,一口氣不費勁,推薦使用。

簡潔的函式式無狀態元件

我們可以使用 ES6 的 arrow functions 讓元件的定義更加的清新。假如我們有一個這樣的元件:

我們可以將其用 ES6 的語法改寫升級一下:

還可以再簡單嗎,我們來試一試:

但這種方式就只允許我們的元件只有 props 作為輸入,elements 作為輸出。但如果我們希望在這中間做一些業務邏輯呢,我們可以將其再修改一下:

回過頭來看看,箭頭函式真是在我們定義無狀態元件的時候幫了大忙,整個世界的清爽了。

木偶元件Presenter Component和容器元件Container Component

好吧,這兩個詞聽起來實在是彆扭,聽我慢慢道來。

React 中的元件其實也只是應用狀態的一種表現方式,這讓我們可以非常清晰的通過 (State) => View 這樣的方式來理解。並且,元件內由處理程式來改變 state,從而改變不同 view 的展示。

那麼,木偶元件和容器元件有什麼區別或是怎麼理解呢。

  • 木偶元件只接受傳遞進來的 props 和 callback,然後返回對應需要展示的 view,這種元件比較單純,大部分都是無狀態元件,給我啥我就展示啥,給我什麼callback我就執行callback,相同的輸入總能得到相同的輸出,像個機器人或是像個木偶,很純粹很簡單很可控;
  • 而容器元件內更多的是關注邏輯,你需要在容器元件中準備好資料和一些callbac函式,在這裡處理一些事件或管理內部的狀態,給木偶元件傳遞所需的資料,大致的意思就是,容器元件對木偶元件說:排程或是邏輯處理的事就交給我吧,你需要啥我給你啥,你安心幹你的活就行,保證給我的產出即可。

當專案中使用了Redux的時候,Container Component 有個更好理解的名字,就是Connected Component。這類元件和Redux的store進行了連線,並且獲取到store的資料之後進行一些操作後傳遞給子元件。

Container components容器元件關注事情是怎麼做的,Presenter components木偶元件關注怎麼展現,各司其職,其樂融融。

另外,也再推薦給一篇文章smart-and-dumb-components,可以再更深入的理解。

什麼時候該用 Container Components 容器元件呢

前面聊完,我想你應該知道兩者的區別和使用場景了,但也許你還不太確定什麼時候該用什麼型別的元件。你可以定義一個Container Components,然後把一些Presenter Components都作為他的子元件,這樣父元件關注如何工作,子元件關注如何展現。

但慢慢的,你發現父元件需要給子元件傳遞的properties和callbacks越來越多了,咋辦呢,現在是時候來介紹兩者如何結合使用了。

一般地,有個很好的原則:堅持presenter components不變,只新增一系列的container components去適應業務邏輯的改變。

把container component放到什麼地方呢

  1. 父元件container component只關注state如何處理,現在你可以評估一下你的preenter component下面的子元件了。也許你會注意到preenter component下面的子元件沒有被其他元件使用,那麼找到這個元件的父元件,給它新增一個用於管理狀態的container component,這樣,父級的container component就能夠變得更加清晰輕量,因為它沒有必要去處理這些所有的狀態。
  2. 很多presenters component也許只是包含一些只是為他們自己使用的props和callbacks,那麼,也給他們加上一個container component去處理這些邏輯,把這些邏輯放到container component,這樣將使父級的container component 再次變得輕量。

寫出你的第一個高階元件HOC吧

想象一下你需要展示一列內容,但是你不得不首先通過非同步的方式獲取這些內容項。現在你需要一個載入指示器來顯示目前正在傳送請求中,等請求完成後,你再展示獲取到的內容項。

不過你可以更進一步來學習HOC了,一個高階元件HOC將會返回一個增強的函式。

高階元件很強大,但是我們也得有目的的去使用。另外,recompose提供了一系列非常有用的高階元件,在開始寫你自己的高階元件的時候,不妨先去這裡看看,學習一下,也許就能解決你的疑惑了。

帶有業務邏輯的樣式名管理

也許你在元件中遇到了這樣帶有條件邏輯的樣式名定義:

這種情況我們可以使用 classnames 來處理,這會讓我們可以非常方便的在elements上定義有條件的style:

React 中的動畫 Animations

通過這個小例子來感受一下React animationreact-motion 給我們提供了一個在 react 中使用動畫效果的工具包。但是,我發現這個學習曲線非常陡峭,在你開始使用 React Motion 之後就會讓人覺得非常沮喪。不過一旦你寫出一個流暢的可拖放動畫之後你會感覺很有成就感。

其實,對於大多數前端小夥伴們來說,我們也只是花很少一部分時間在動畫效果的實現上面,所以當你本身不會經常使用這個動畫庫的時候,等到下次需要用到的時候又得重新熟悉一遍,這也造成了學習曲線反覆的問題。

另外,velocity-react 是基於Velocity DOM animation 實現的另外一個React動畫庫,你可以在 React Motion和它之間二選一。

編後語

如果你想系統學習 React + Redux 技術棧的所有內容,請點我前往

相關文章