這一篇,我們將介紹 React 中最重要的概念之一 —— 組件。
元素與組件(Element & Component) 元素
元素是構建 React 應用的最小單位。元素所描述的也就是你在瀏覽器中能夠看到的東西。
我們在編寫 React 代碼時一般用 JSX 來描述 React 元素。
在作用上,我們可以把 React 元素理解為 DOM 元素,但實際上,React 元素只是 JS 當中普通的對象。React 內部實現了一套叫做 React DOM 的東西,或者我們稱之為 Virtual DOM 也就是虛擬 DOM.通過一個樹狀結構的 JS 對象來模擬 DOM 樹。
React 之所以快就是因為這一套虛擬 DOM 的存在,React 內部還實現了一個低複雜度高效率的 Diff 算法,不同於以往框架,例如 Angular 使用的髒檢查。在應用的數據改變之後,React 會盡力少地比較,然後根據虛擬 DOM 只改變真實 DOM 中需要被改變的部分。並且通過這一層單獨抽象的邏輯讓 React 有了無限的可能,就比如 react native 的實現。
組件
要注意到,在 React 當中元素和組件是兩個不同的概念,我們需要明確的是,組件是構建在元素的基礎之上的。
React 官方對組件的定義,是指在 UI 界面中,可以被獨立劃分的、可復用的、獨立的模塊。
其實就類似於 JS 當中對 function 函數的定義,它一般會接收一個名為 props 的輸入,然後返回相應的 React 元素,再交給 ReactDOM,最後渲染到屏幕上。
函數定義與類定義組件(Functional & Class)
React 提供了兩種定義組件的方法:
函數定義組件,只需要定義一個接收 props 傳值,返回 React 元素的方法即可:
類定義組件,也就是使用 ES6 中新引入的類的概念來定義 React 組件:
組件在定義好之後,可以通過 JSX 描述的方式被引用,組件之間也可以相互嵌套和組合。
展示與容器組件(Presentational & Container)
之前我們說過,React 不算是一個框架,他只關心視圖層次,因此,他是如何處理數據與視圖關係呢?為了解決這一問題,就引入了展示組件和容器組件的概念。這是我們在開發 React 應用時的最佳實踐。
這是一個回複列表組件,乍看上去很正常也很合理。但實際上在開發 React 應用時,我們應該避免寫出這樣的組件,因為這類組件擔負的功能太多了。
它只是一個單一的組件,但需要同時負責初始化 state,通過 ajax 獲取伺服器數據,渲染列表內容,在實際應用中,可能還會有更多的功能依賴。
通過應用展示組件與容器組件的概念,我們可以把上述的單一組件重構為一個展示回複列表組件和回複列表容器:
這樣單一組件就分割成兩個組件了。
我們再來明確一下展示組件和容器組件的概念:
展示組件
主要負責組建內容如何展示
從 props 接收父組件傳遞的數據
大多數可以通過函數定義組件聲明
容器組件
主要關注組件數據如何交互
擁有自身的 state,從伺服器獲取數據,或與 redux 等其他數據處理模塊協作
需要通過類定義組件聲明,並包含生命周期函數和其他附加方法
有狀態與無狀態組件(Stateful & Stateless)
有狀態組件
有狀態的意思是這個組件能夠獲取儲存改變應用或組件本身的狀態數據,在 React 當中也就是 state,一些比較明顯的特徵是我們可以在這樣的組件當中看到對 this.state 的初始化,或 this.setState 方法的調用等等。
無狀態組件
這樣的組件一般只接收來自其他組件的數據。一般這樣的組件中只能看到對 this.props 的調用,通常可以用函數定義組件的方式聲明。
注意:並不是所有的展示組件都是無狀態組件,所有的容器組件都是有狀態組件。
受控與非受控組件(Controlled & Uncontrolled)
受控組件
一般涉及到表單元素時我們才會使用這種分類方法,受控組件的值由 props 或 state 傳入,用戶在元素上交互或輸入內容會引起應用 state 的改變。在 state 改變之後重新渲染組件,我們才能在頁面中看到元素中值的變化,假如組件沒有綁定事件處理函數改變 state,用戶的輸入是不會起到任何效果的,這也就是"受控"的含義所在。
非受控組件
類似於傳統的 DOM 表單控制項,用戶輸入不會直接引起應用 state 的變化,我們也不會直接為非受控組件傳入值。想要獲取非受控組件,我們需要使用一個特殊的 ref 屬性,同樣也可以使用 defaultValue 屬性來為其指定一次性的默認值。
注意:通常情況下,React 當中所有的表單控制項都需要是受控組件。但正如我們對受控組件的定義,想讓受控組件正常工作,每一個受控組件我們都需要為其編寫事件處理函數。
組合與繼承(Composition & Inheritance)
React 當中的組件是通過嵌套或組合的方式實現組件代碼復用的。通過 props 傳值和組合使用組件幾乎可以滿足所有場景下的需求。這樣也更符合組件化的理念,就好像使用互相嵌套的 DOM 元素一樣使用 React 的組件,並不需要引入繼承的概念。
React 官方也希望我們通過組合的方式來使用組件,如果你想實現一些非界面類型函數的復用,可以單獨寫在其他的模塊當中在引入組件進行使用。